La programmation fonctionnelle repose sur des fonctions pures
La programmation fonctionnelle écrit un programme comme un ensemble de fonctions pures : une fonction rend toujours le même résultat pour les mêmes arguments. Haskell est le langage qui pousse cette idée le plus loin, et chaque fonction y a un type.
Dans une boutique, une fonction qui retire 10 % d’un prix ne change aucun prix en cachette. Elle prend un prix et rend un autre prix. On la teste donc sans rien préparer.
À la fin de cette leçon
Remarque
Je peux lire une petite fonction Haskell et son type.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Fonction pure | une fonction dont le résultat ne dépend que de ses arguments | |
| Effet de bord | un changement hors du résultat, comme afficher ou modifier une variable | |
| Type | le genre d’une valeur | Int |
| Signature | la ligne qui donne les types d’une fonction | square :: Int -> Int |
| Application | donner un argument à une fonction, sans parenthèses en Haskell | square 12 |
| Composition | enchaîner deux fonctions avec un point | (f . g) x |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Une fonction pure ne change rien d’autre
Une fonction pure ne dépend que de ses arguments. Elle ne modifie aucune variable et n’affiche rien : elle rend une valeur.
Une action comme afficher à l’écran est un effet de bord. Haskell la sépare des fonctions pures, ce qui rend les fonctions faciles à tester et à combiner. En Haskell, on écrit square 12 pour appliquer square à 12, sans parenthèses.
Trois fonctions du fichier Basics.hs
-- Basics.hs : la ligne avec :: est la signature de type.
square :: Int -> Int
square n = n * n
greet :: String -> String
greet name = "Hello, " ++ name ++ "!"
isEven :: Int -> Bool
isEven n = mod n 2 == 0
Ce que GHC écrit reste en anglais
Dans ce labo, Haskell est le compilateur GHC. Les mots qu’il écrit, comme True, False ou les messages d’erreur, restent en anglais.
La commande docker exec haskell lance GHC dans la machine du labo. runghc exécute un fichier. ghc -e calcule une seule expression, ici avec Basics.hs chargé.
Lancer le fichier Basics.hs
docker exec haskell runghc Basics.hsAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Appliquer square à 12
docker exec haskell ghc -e "square 12" Basics.hsAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Sept est-il pair ?
docker exec haskell ghc -e "isEven 7" Basics.hsAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Une signature donne les types d’une fonction
Une signature s’écrit avec ::, qui se lit « a pour type ». Les types des arguments et du résultat sont séparés par des flèches.
square :: Int -> Int se lit : square prend un entier et rend un entier. Le dernier type de la ligne est toujours le résultat. GHC vérifie les types avant d’exécuter quoi que ce soit.
Exemple travaillé : lire une signature
| Signature | Elle se lit | Un appel |
|---|---|---|
| square :: Int -> Int | Prend un entier, rend un entier | square 12 |
| isEven :: Int -> Bool | Prend un entier, rend vrai ou faux | isEven 7 |
| greet :: String -> String | Prend un texte, rend un texte | greet "Marie" |
| map :: (a -> b) -> [a] -> [b] | Prend une fonction et une liste, rend une liste | map (+ 1) [10, 20] |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Le type de square
docker exec haskell ghc -e ":t square" Basics.hsAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Le type de map
docker exec haskell ghc -e ":t map"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Saluer Marie
docker exec haskell ghc -e 'greet "Marie"' Basics.hsAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Une faute de type, première ligne
docker exec haskell ghc -e '1 + "a"' 2>&1 | head -n 1Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
La composition enchaîne deux fonctions
Le point . compose deux fonctions : (f . g) x veut dire f (g x). D’abord g travaille, puis f reçoit son résultat.
Pour que cela marche, le résultat de g doit avoir le type que f attend. Le type de . le dit : il prend deux fonctions et en rend une troisième.
Exemple travaillé : (length . show) 12345
| Étape | Fonction | Ce qu’elle reçoit | Ce qu’elle rend |
|---|---|---|---|
| 1 | show | 12345, un nombre | "12345", un texte |
| 2 | length | "12345" | 5, la longueur du texte |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Composer length et show
docker exec haskell ghc -e "(length . show) 12345"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Le type du point
docker exec haskell ghc -e ":t (.)"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Erreur fréquente
Attention
Beaucoup de gens pensent que n = n + 1 ajoute un à n, comme en Python. En Haskell, = veut dire « est défini comme » : un nom garde sa valeur pour toujours. Cette ligne dirait que n est égal à n plus un, ce qui n’a pas de sens.
Pour aller plus loin
Dans le labo, ouvrez le terminal et tapez docker exec -it haskell ghci Basics.hs. Le prompt de GHC attend vos expressions : tapez square 9, puis :t greet.
Quittez avec :quit. Ajoutez ensuite à une copie du fichier une fonction triple :: Int -> Int et appelez-la.