f# - implícito - Propósito de una unión discriminada por un solo caso
ejemplos de implícito y explícito (2)
Estoy definiendo un analizador sintáctico / reactivo monádico. Esto se comporta de manera bastante diferente a un analizador normal, ya que es una consulta continua. El tipo subyacente es:
IObservable<''a> -> IObservable<''b>
Al observar varias implementaciones de analizador en lenguajes funcionales, parece que la forma más apropiada de definir las cosas es una unión discriminada de un solo caso:
type Pattern<''a,''b> = Pattern of (IObservable<''a> -> IObservable<''b>)
Lo que significa que luego necesito extraer la función subyacente para usarla:
let find (Pattern p) = p
La pregunta es: ¿es esto solo por convención, o para fines de extensión posterior, o hay una razón para hacer esto incluso si la definición nunca cambia?
Pregunta de bonificación: si solo se trata de una firma de tipo más conveniente, ¿por qué no utilizar un alias tipo?
type Pattern<''a,''b> = IObservable<''a> -> IObservable<''b>
He avanzado bastante en esto y no he encontrado ningún caso en el que la capacidad de compilación se vea afectada al no usar el DU.
Por lo que entiendo, el tipo de unión discriminada por un solo caso está ahí para proporcionar un nombre que sea semánticamente relevante para su dominio problemático, a un tipo de backend de propósito general cuyo nombre es ''cadena''.
Es una corrección de fuga de abstracción ligera para semántica, y solo eso, AFAIK
El compilador de F # no conserva la información sobre la abreviatura de tipo, por lo que no se beneficia de la inferencia de tipo en absoluto. La firma del tipo se puede entender como la especificación del programa; Permitir que el verificador de tipos haga su trabajo es una buena forma de garantizar la corrección de sus programas.
Debe especificar explícitamente la anotación de tipo en todas partes en el caso de alias de tipo:
type Vector = float * float
// val add : float * float -> float * float -> Vector
let add ((x1, y1): Vector) ((x2, y2): Vector): Vector = (x1 + y1, x2 + y2)
pero no le da transparencia como el uso de DU:
type Vector = V of float * float
// val add : Vector -> Vector -> Vector
let add (V(x1, y1)) (V(x2, y2)) = V(x1 + y1, x2 + y2)
En los programas complejos, las firmas claras de tipo de hecho facilitan el mantenimiento de la compibilidad.
No solo es más sencillo agregar más casos a DU de un solo caso, sino que también es más fácil extender DU con métodos estáticos y miembros. Un ejemplo es que a menudo anula ToString()
para una impresión bonita.