L'objectif de cette deuxième séance est de savoir créer ses propres types et de se familiariser avec l'architecture elm pour créer une application web monopage.
La première chose que tu dois faire, c'est de lire attentivement la section du guide consacré aux types.
Je te propose ci-dessous rappel et une série d'exercices pour que tu t'entraines à créer tes propres types. C'est très important pour la suite.
Les types algébriques, appelés custom types dans le guide, sont une combinaison de :
- type somme (ou encore union, enum, etc.), comme
type Couleur = Rouge | Noir
, - type produit (qui ne sont rien d'autres que des tuples personnalisés), comme
type Point = DonnePoint Float Float
, - et récursivité.
Avant de donner plus d'exemples, mettons-nous d'accord sur les mots. A gauche du =
, c'est le monde des types. On a un constructeur de type. A droite du =
, on a le monde des valeurs. On a une liste de constructeurs de valeurs séparés par des |
. Un constructeur de valeur peut avoir zéro paramètre (Rouge
, Noir
) ou plusieurs paramètres (Point Float Float
a deux paramètres, chacun de type Float
). Pour obtenir une valeur, on appelle le constructeur de valeur :
> type Couleur = Rouge | Noir
> type Point = DonnePoint Float Float
> Rouge
Rouge : Couleur
> DonnePoint 3.2 5.4
DonnePoint 3.2 5.4 : Point
Tous les constructeurs commencent par une majuscule. Comme il y a des espaces de noms séparés pour les constructeurs de types et de valeurs, on peut aussi écrire :
> type Point = Point Float Float
> Point 3.2 5.4
Point 3.2 5.4 : Point
Par ailleurs, les types algébriques peuvent être paramétrés par des types variables, toujours notés en minuscules. Le constructeur de type peut avoir zéro paramètre (comme pour Couleur
, Point
), ou plusieurs, comme pour ces types, déjà définis dans elm et fondamentaux pour la gestion des erreurs:
type Maybe a = Just a | Nothing
type Result error value = Ok value | Err error
Dans le premier cas, il n'y a qu'un seul type variable, noté a
(on choisit souvent a
pour un type variable), dans le second, il y en deux, nommés error
et value
. Pour construire des valeurs pour ces types, il suffit d'appeler les constructeurs de valeurs :
> Just 'c'
Just 'c' : Maybe Char
> Just 5.2
Just 5.2 : Maybe Float
> Nothing
Nothing : Maybe a
> Ok "it works!"
Ok ("it works!") : Result error String
> Err "it fails!"
Err ("it fails!") : Result String value
Enfin, les types algébriques peuvent être récursifs : le type qu'on définit (à gauche) apparait comme paramètre d'un constructeur de valeur (à droite) comme dans l'exemple ci-dessous :
> type StackInt = Empty | Push Int StackInt
> s = Push 5 Empty
Push 5 Empty : StackInt
> Push 3 s
Push 3 (Push 5 Empty) : StackInt
Le type StackInt
ne peut traiter que des Int
. Pour lever cette contrainte, il suffit d'opter pour un type paramétré :
type Stack a = Empty | Push a (Stack a)
On peut ainsi créé une valeur de type Stack Char
ou une valeur de type Stack Int
:
> aStack = Push 'b' (Push 'a' Empty)
Push 'b' (Push 'a' Empty)
: Stack Char
> aStack = Push 2 (Push 1 Empty)
Push 2 (Push 1 Empty)
: Stack number
N'est-ce pas grisant de définir en une ligne une structure de données représentant des piles d'éléments de type arbitraire ?
- Donne, pour chacun des cinq types précédents (
Couleur
,Point
,Maybe
,Result
,StackInt
), le constructeur de type, ses paramètres, la liste des constructeurs de valeurs et leurs paramètres. - Propose un type
CouleurCarte
pour modéliser la couleur (ou enseigne) d'une carte à jouer. - Propose un type
ValeurCarte
pour modéliser la valeur d'une carte à jouer. - Propose un type
Carte
pour modéliser une carte à jouer. - Crée la carte correspondant à l'as de Trèfle, puis crée la liste des quatre as.
- Propose un type paramétré
Tree
pour modéliser un arbre binaire. Puis, crée un arbre vide, ainsi qu'un arbre contenant au moins trois nombres flottants. Enfin, écris une fonction qui retourne la hauteur d'une arbre.
Maintenant, je t'invite à lire attentivement la section du guide consacré à l'architecture elm et à faire les exercices associés. Ces exercices ne sont pas corrigés, mais pas trop difficiles. Si tu es bloqué, demande conseil à quelqu'un ou contacte l'enseignant.
- Qu'est-ce que le pattern matching ?
- Quelle est la différence entre un tuple, un enregistrement, une liste ?
- Qu'est-ce qu'un type algébrique ?
- Quels sont les types et fonctions nécessaires pour
browser.sandbox
?
Compare tes réponses avec ce document, celui de la séance précédente et le guide.
Si tu as déjà fini et qu'il reste du temps, tu peux regarder les exemples, lire la section error handling et te pencher sur les parseurs. S'il te reste encore du temps après ça, tu peux regarder la section commands and subscriptions et commencer à réfléchir au projet.
type Couleur = Rouge | Noir
- un constructeur de type sans paramètre
Couleur
- deux constructeurs de valeur sans paramètre :
Rouge
etNoir
type Point = Point Float Float
- un constructeur de type sans paramètre
Point
(celui de gauche) - un constructeur de valeur
Point
(celui de droite) prenant deux paramètres de typeFloat
en entrée.
type Maybe a = Just a | Nothing
- un constructeur de type
Maybe
prenant en paramètre un typea
, généralement appelé type variable. - deux constructeurs de valeur :
- un sans paramètre :
Nothing
, - et
Just
prenant un paramètre de typea
- un sans paramètre :
On peut rapprocher Maybe
de List
: tous deux représentent des conteneurs paramétrés par un autre type.
type Result error value = Ok value | Err error
- un constructeur de type
Result
prenant deux types en paramètreerror
etvalue
- deux constructeurs de valeur :
Ok
prend en paramètrevalue
,Err
prend en paramètreerror
.
type StackInt = Empty | Push Int StackInt
- un constructeur de type sans paramètre
StackInt
(celui de gauche) - deux constructeurs de valeurs :
Empty
est sans paramètre,Push
prend deux paramètres, un de typeInt
et un de typeStackInt
.
Le type StackInt
ne peut traiter que des Int
. On peut lever cette contrainte à l'aide d'un type paramétré type Stack a = Empty | Push a (Stack a)
. On remplace Int
par un type variable appelé a
et StackInt
par Stack a
. C'est d'ailleurs la réponse à l'une des questions suivantes.
Voir le fichier Test.elm