Comment j'y pense:
type
est utilisé pour définir de nouveaux types d'union:
type Thing = Something | SomethingElse
Avant cette définition Something
et SomethingElse
ne signifiait rien. Maintenant, ils sont tous les deux de type Thing
, que nous venons de définir.
type alias
est utilisé pour donner un nom à un autre type qui existe déjà:
type alias Location = { lat:Int, long:Int }
{ lat = 5, long = 10 }
a un type { lat:Int, long:Int }
, qui était déjà un type valide. Mais maintenant, nous pouvons également dire qu'il a un type Location
car c'est un alias pour le même type.
Il est à noter que ce qui suit se compilera très bien et s'affichera "thing"
. Même si nous spécifions thing
est a String
et aliasedStringIdentity
prend an AliasedString
, nous n'obtiendrons pas d'erreur indiquant qu'il y a une incompatibilité de type 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
{}
syntaxe d'enregistrement, vous définissez un nouveau type?{ lat:Int, long:Int }
ne définit pas un nouveau type. C'est déjà un type valide.type alias Location = { lat:Int, long:Int }
ne définit pas non plus un nouveau type, il donne simplement un autre nom (peut-être plus descriptif) à un type déjà valide.type Location = Geo { lat:Int, long:Int }
définirait un nouveau type (Location
)La clé est le mot
alias
. Au cours de la programmation, lorsque vous souhaitez regrouper des éléments qui vont ensemble, vous le mettez dans un enregistrement, comme dans le cas d'un pointou un dossier étudiant.
Maintenant, si vous aviez besoin de transmettre ces enregistrements, vous devrez épeler le type entier, comme:
Si vous pouviez alias un point, la signature serait tellement plus facile à écrire!
Un alias est donc un raccourci pour autre chose. Ici, c'est un raccourci pour un type d'enregistrement. Vous pouvez y penser comme donner un nom à un type d'enregistrement que vous utiliserez souvent. C'est pourquoi on l'appelle un alias - c'est un autre nom pour le type d'enregistrement nu représenté par
{ x:Int, y:Int }
Alors que
type
résout un problème différent. Si vous venez de la POO, c'est le problème que vous résolvez avec l'héritage, la surcharge d'opérateurs, etc. - parfois, vous voulez traiter les données comme une chose générique, et parfois vous voulez les traiter comme une chose spécifique.Un lieu courant où cela se produit est lors de la transmission de messages - comme le système postal. Lorsque vous envoyez une lettre, vous voulez que le système postal traite tous les messages comme la même chose, vous n'avez donc à concevoir le système postal qu'une seule fois. Et en outre, le travail d'acheminement du message doit être indépendant du message contenu à l'intérieur. Ce n'est que lorsque la lettre atteint sa destination que vous vous souciez de la nature du message.
De la même manière, nous pourrions définir a
type
comme une union de tous les différents types de messages qui pourraient arriver. Disons que nous mettons en place un système de messagerie entre les étudiants et leurs parents. Il n'y a donc que deux messages que les étudiants peuvent envoyer: «J'ai besoin de bière» et «J'ai besoin de sous-vêtements».Alors maintenant, lorsque nous concevons le système de routage, les types de nos fonctions peuvent simplement passer
MessageHome
, au lieu de se soucier de tous les différents types de messages que cela pourrait être. Le système de routage s'en fiche. Il suffit de savoir que c'est un fichierMessageHome
. Ce n'est que lorsque le message atteint sa destination, la maison du parent, que vous devez comprendre de quoi il s'agit.Si vous connaissez l'architecture Elm, la fonction de mise à jour est une instruction de cas géante, car c'est la destination d'où le message est acheminé, et donc traité. Et nous utilisons des types d'union pour avoir un seul type à traiter lors de la transmission du message, mais nous pouvons ensuite utiliser une instruction case pour déterminer exactement de quel message il s'agissait, afin que nous puissions le traiter.
la source
Permettez-moi de compléter les réponses précédentes en me concentrant sur les cas d'utilisation et en fournissant un peu de contexte sur les fonctions et les modules du constructeur.
Usages de
type alias
Créer un alias et une fonction constructeur pour un enregistrement
C'est le cas d'utilisation le plus courant: vous pouvez définir un autre nom et une fonction constructeur pour un type particulier de format d'enregistrement.
La définition de l'alias de type implique automatiquement la fonction constructeur suivante (pseudo code):
Person : String -> Int -> { name : String, age : Int }
Cela peut être utile, par exemple lorsque vous souhaitez écrire un décodeur Json.
Spécifiez les champs obligatoires
Ils appellent parfois cela des «enregistrements extensibles», ce qui peut être trompeur. Cette syntaxe peut être utilisée pour spécifier que vous attendez un enregistrement avec des champs particuliers présents. Tel que:
Ensuite, vous pouvez utiliser la fonction ci-dessus comme ceci (par exemple dans votre vue):
La conférence de Richard Feldman sur ElmEurope 2017 peut fournir un aperçu supplémentaire du moment où ce style vaut la peine d'être utilisé.
Renommer des éléments
Vous pouvez le faire, car les nouveaux noms pourraient fournir une signification supplémentaire plus tard dans votre code, comme dans cet exemple
Un meilleur exemple de ce type d'utilisation dans le noyau est peut-être
Time
.Réexposer un type à partir d'un module différent
Si vous écrivez un package (pas une application), vous devrez peut-être implémenter un type dans un module, peut-être dans un module interne (non exposé), mais vous souhaitez exposer le type à partir de un autre module (public). Ou bien, vous souhaitez exposer votre type à partir de plusieurs modules.
Task
dans core et Http.Request dans Http sont des exemples pour le premier, tandis que Json.Encode.Value et Json.Decode.Value paire est un exemple de la dernière.Vous ne pouvez le faire que si vous souhaitez autrement garder le type opaque: vous n'exposez pas les fonctions du constructeur. Pour plus de détails, voir les utilisations
type
ci - dessous.Il est à noter que dans les exemples ci-dessus, seul le # 1 fournit une fonction constructeur. Si vous exposez votre alias de type dans # 1 comme
module Data exposing (Person)
cela, vous exposez le nom du type ainsi que la fonction constructeur.Usages de
type
Définir un type d'union balisé
C'est le cas d'utilisation le plus courant, un bon exemple de celui-ci est le
Maybe
type dans le noyau :Lorsque vous définissez un type, vous définissez également ses fonctions de constructeur. Dans le cas de Maybe, ce sont (pseudo-code):
Ce qui signifie que si vous déclarez cette valeur:
Vous pouvez le créer soit
ou
Les balises
Just
etNothing
ne servent pas seulement de fonctions de constructeur, elles servent également de destructeurs ou de modèles dans unecase
expression. Ce qui signifie qu'en utilisant ces modèles, vous pouvez voir à l'intérieur d'unMaybe
:Vous pouvez le faire, car le module Maybe est défini comme
Cela pourrait aussi dire
Les deux sont équivalents dans ce cas, mais être explicite est considéré comme une vertu dans Elm, en particulier lorsque vous écrivez un package.
Masquer les détails de l'implémentation
Comme indiqué ci-dessus, c'est un choix délibéré que les fonctions du constructeur
Maybe
sont visibles pour les autres modules.Il y a cependant d'autres cas où l'auteur décide de les cacher. Un exemple de ceci dans le noyau est
Dict
. En tant que consommateur du package, vous ne devriez pas être en mesure de voir les détails d'implémentation de l'algorithme d'arbre rouge / noir derrièreDict
et de jouer directement avec les nœuds. Le masquage des fonctions constructeur oblige le consommateur de votre module / package à créer uniquement des valeurs de votre type (puis à transformer ces valeurs) via les fonctions que vous exposez.C'est la raison pour laquelle parfois des trucs comme celui-ci apparaissent dans le code
Contrairement au
type alias
définition en haut de cet article, cette syntaxe crée un nouveau type "union" avec une seule fonction constructeur, mais cette fonction constructeur peut être masquée des autres modules / packages.Si le type est exposé comme ceci:
Seul le code du
Data
module peut créer une valeur Person et seul ce code peut correspondre au modèle.la source
La principale différence, comme je le vois, est de savoir si le vérificateur de type crie sur vous si vous utilisez le type "synomical".
Créez le fichier suivant, placez-le quelque part et exécutez
elm-reactor
, puis accédez àhttp://localhost:8000
pour voir la différence:Si vous décommentez
2.
et commentez,1.
vous verrez:la source
An
alias
est juste un nom plus court pour un autre type, similaireclass
en POO. Exp:Un
type
(sans alias) vous permettra de définir votre propre type, de sorte que vous pouvez définir des types tels queInt
,String
... app pour vous. Par exemple, dans le cas courant, il peut utiliser pour la description d'un état de l'application:Ainsi, vous pouvez facilement le manipuler en
view
orme:Je pense que vous connaissez la différence entre
type
ettype alias
.Mais pourquoi et comment utiliser
type
ettype alias
est important avec l'elm
application, vous pouvez vous référer à l' article de Josh Claytonla source