Cómo lo pienso:
type
se utiliza para definir nuevos tipos de unión:
type Thing = Something | SomethingElse
Antes de esta definición Something
y SomethingElse
no significaba nada. Ahora ambos son del tipo Thing
, que acabamos de definir.
type alias
se usa para dar un nombre a algún otro tipo que ya existe:
type alias Location = { lat:Int, long:Int }
{ lat = 5, long = 10 }
tiene tipo { lat:Int, long:Int }
, que ya era un tipo válido. Pero ahora también podemos decir que tiene tipoLocation
porque es un alias para el mismo tipo.
Vale la pena señalar que lo siguiente se compilará y mostrará sin problemas "thing"
. Aunque especificamos thing
is a String
y aliasedStringIdentity
toma an AliasedString
, no obtendremos un error de que existe una falta de coincidencia de tipos entre String
/ AliasedString
:
import Graphics.Element exposing (show)
type alias AliasedString = String
aliasedStringIdentity: AliasedString -> AliasedString
aliasedStringIdentity s = s
thing : String
thing = "thing"
main =
show <| aliasedStringIdentity thing
{}
sintaxis de registro, ¿está definiendo un nuevo tipo?{ lat:Int, long:Int }
no define un nuevo tipo. Ese ya es un tipo válido.type alias Location = { lat:Int, long:Int }
tampoco define un nuevo tipo, solo le da otro nombre (quizás más descriptivo) a un tipo ya válido.type Location = Geo { lat:Int, long:Int }
definiría un nuevo tipo (Location
)La clave es la palabra
alias
. En el curso de la programación, cuando quieres agrupar cosas que pertenecen juntas, lo pones en un registro, como en el caso de un puntoo un expediente de estudiante.
Ahora, si necesita pasar estos registros, tendrá que deletrear todo el tipo, como:
Si pudieras poner un alias en un punto, ¡la firma sería mucho más fácil de escribir!
Entonces, un alias es una forma abreviada de otra cosa. Aquí, es una abreviatura de un tipo de registro. Puede pensar en ello como dar un nombre a un tipo de registro que utilizará con frecuencia. Por eso se llama alias: es otro nombre para el tipo de registro desnudo que está representado por
{ x:Int, y:Int }
Considerando que
type
resuelve un problema diferente. Si viene de OOP, es el problema que resuelve con la herencia, la sobrecarga de operadores, etc., a veces, desea tratar los datos como algo genérico y, a veces, desea tratarlos como algo específico.Un lugar común donde esto sucede es cuando se transmiten mensajes, como el sistema postal. Cuando envía una carta, desea que el sistema postal trate todos los mensajes como lo mismo, por lo que solo tiene que diseñar el sistema postal una vez. Y además, el trabajo de enrutar el mensaje debe ser independiente del mensaje que contiene. Solo cuando la carta llega a su destino te importa cuál es el mensaje.
De la misma manera, podríamos definir a
type
como una unión de todos los diferentes tipos de mensajes que podrían ocurrir. Digamos que estamos implementando un sistema de mensajería entre estudiantes universitarios y sus padres. Así que solo hay dos mensajes que los universitarios pueden enviar: "Necesito dinero para cerveza" y "Necesito calzoncillos".Así que ahora, cuando diseñamos el sistema de enrutamiento, los tipos de nuestras funciones pueden simplemente pasar
MessageHome
, en lugar de preocuparse por todos los diferentes tipos de mensajes que podrían ser. Al sistema de enrutamiento no le importa. Solo necesita saber que es unMessageHome
. Solo cuando el mensaje llega a su destino, la casa de los padres, es necesario averiguar qué es.Si conoce la arquitectura Elm, la función de actualización es una declaración de caso gigante, porque ese es el destino al que se enruta el mensaje y, por lo tanto, se procesa. Y usamos tipos de unión para tener un solo tipo con el que lidiar cuando se pasa el mensaje, pero luego podemos usar una declaración de caso para averiguar exactamente qué mensaje era, para que podamos lidiar con él.
fuente
Permítanme complementar las respuestas anteriores centrándome en casos de uso y proporcionando un pequeño contexto sobre las funciones y los módulos del constructor.
Usos de
type alias
Crear un alias y una función constructora para un registro
Este es el caso de uso más común: puede definir un nombre alternativo y una función constructora para un tipo particular de formato de registro.
Definir el alias de tipo implica automáticamente la siguiente función constructora (pseudocódigo):
Person : String -> Int -> { name : String, age : Int }
Esto puede resultar útil, por ejemplo, cuando se desea escribir un decodificador Json.
Especifique los campos obligatorios
A veces lo llaman "registros extensibles", lo que puede resultar engañoso. Esta sintaxis se puede utilizar para especificar que está esperando algún registro con campos particulares presentes. Como:
Entonces puede usar la función anterior de esta manera (por ejemplo, en su vista):
La charla de Richard Feldman sobre ElmEurope 2017 puede proporcionar más información sobre cuándo vale la pena usar este estilo.
Cambiar el nombre de las cosas
Puede hacer esto, porque los nuevos nombres podrían proporcionar un significado adicional más adelante en su código, como en este ejemplo
Quizás un mejor ejemplo de este tipo de uso en core es
Time
.Volver a exponer un tipo de un módulo diferente
Si está escribiendo un paquete (no una aplicación), es posible que necesite implementar un tipo en un módulo, tal vez en un módulo interno (no expuesto), pero desea exponer el tipo de un módulo (público) diferente. O, alternativamente, desea exponer su tipo de varios módulos.
Task
en core y Http.Request en Http son ejemplos del primero, mientras que Json.Encode.Value y Json.Decode.Value par es un ejemplo del último.Solo puede hacer esto cuando, de lo contrario, desea mantener el tipo opaco: no expone las funciones del constructor. Para obtener más información, consulte los usos a
type
continuación.Vale la pena notar que en los ejemplos anteriores solo el # 1 proporciona una función de constructor. Si expone su alias de tipo en # 1 así
module Data exposing (Person)
, expondrá el nombre del tipo así como la función constructora.Usos de
type
Definir un tipo de unión etiquetada
Este es el caso de uso más común, un buen ejemplo de ello es el
Maybe
tipo en el núcleo :Cuando define un tipo, también define sus funciones de constructor. En el caso de Maybe, estos son (pseudocódigo):
Lo que significa que si declaras este valor:
Puede crearlo por
o
Las etiquetas
Just
yNothing
no solo sirven como funciones de constructor, también sirven como destructores o patrones en unacase
expresión. Lo que significa que usando estos patrones puedes ver dentro de unMaybe
:Puede hacer esto, porque el módulo Quizás se define como
También podría decir
Los dos son equivalentes en este caso, pero ser explícito se considera una virtud en Elm, especialmente cuando está escribiendo un paquete.
Ocultar detalles de implementación
Como se señaló anteriormente, es una elección deliberada que las funciones del constructor
Maybe
sean visibles para otros módulos.Sin embargo, hay otros casos en los que el autor decide ocultarlos. Un ejemplo de esto en el núcleo es
Dict
. Como consumidor del paquete, no debería poder ver los detalles de implementación del algoritmo del árbol Rojo / Negro detrásDict
y meterse con los nodos directamente. Ocultar las funciones del constructor obliga al consumidor de su módulo / paquete a crear solo valores de su tipo (y luego transformar esos valores) a través de las funciones que expone.Esta es la razón por la que a veces aparecen cosas como esta en el código
A diferencia de la
type alias
definición en la parte superior de esta publicación, esta sintaxis crea un nuevo tipo de "unión" con solo una función de constructor, pero esa función de constructor se puede ocultar de otros módulos / paquetes.Si el tipo se expone así:
Solo el código del
Data
módulo puede crear un valor de Persona y solo ese código puede coincidir con el patrón.fuente
La principal diferencia, como yo lo veo, es si el verificador de tipos le gritará si usa el tipo "sinómico".
Cree el siguiente archivo, colóquelo en algún lugar y ejecútelo
elm-reactor
, luego vaya ahttp://localhost:8000
para ver la diferencia:Si descomenta
2.
y comenta1.
, verá:fuente
An
alias
es solo un nombre más corto para algún otro tipo, similarclass
en OOP. Exp:Un
type
(sin alias) le permitirá definir su propio tipo, por lo que se puede definir como tiposInt
,String
... para que usted aplicación. Por ejemplo, en el caso común, se puede usar para la descripción de un estado de aplicación:Para que puedas manejarlo fácilmente en
view
olmo:Creo que conoces la diferencia entre
type
ytype alias
.Pero por qué y cómo usar
type
ytype alias
es importante con laelm
aplicación, ustedes pueden consultar el artículo de Josh Clayton.fuente