Découverte du langage OCaml
Cette semaine j'avais envie d'explorer un nouveau langage. Je souhaitais avoir un typage fort et des fonctions currifiées par défaut : j'ai essayé OCaml, et j'ai été agréablement surpris.
Kata Bowling en OCaml
Pour découvrir le langage, je me suis lancé sur une implémentation du [kata bowling](https://codingdojo.org/kata/Bowling/) :
type roll = Roll of int type frame = Frame of int let next (Frame n) = Frame (n + 1) let rec score ?(f=Frame 1) = function | [] -> 0 | [Roll x; Roll y; Roll z] when is_last_frame f -> x + y + z | r1 :: (Roll y as r2) :: (Roll z as r3) :: rest when is_strike r1 -> 10 + y + z + score ~f:(next f) (r2 :: r3 :: rest) | r1 :: r2 :: (Roll z as r3) :: rest when is_spare r1 r2 -> 10 + z + score ~f:(next f) (r3 :: rest) | Roll x :: Roll y :: rest -> x + y + score ~f:(next f) rest | [_] -> failwith "wrong number of rolls" and is_strike = (=) @@ Roll 10 and is_spare (Roll x) (Roll y) = 10 == x + y and is_last_frame = (=) @@ Frame 10
Le répo github est ici, la liste des commits montre le cheminement :
Ce que j'ai apprécié
- Quand on connait un peu Haskell, on se sent vite à la maison
- La documentation en français]
- Il y a des guidelines et des cheatsheets pour démarrer
- Le paradigme fonctionnel et le pattern matching
- En OCaml, il n'y a que des expressions
- Ne pas avoir à répéter le nom de la fonction pour chaque pattern
- Le pattern matching implicite avec `function`
- Les paramètres nommés et avec valeurs par défaut (voir ci-dessus, `?(f=Frame 1)`)
- Je n'ai pas essayé, mais je suis curieux de l'aspect orienté objet
- L'inférence de type et le typage fort, c'est chouette d'être aidé par un compilateur
- Avoir une erreur de compilation par défaut pour les patterns non exhaustifs et les variables non utilisées
- Le système de build (dune), je n'ai pas eu de mal à le prendre en main (pour ce tout petit projet)
- C'est facile de lancer les tests en mode watch (`dune runtest -w`)
- Installer des libs avec opam, ça fonctionne
- C'est facile de visualiser les erreurs de compilation à la volée dans Vim
- Les sources de gros projets sont dispos pour s'inspirer (JaneStreet et Mirage par exemple)
- OCaml a des variantes plus ou moins populaires, comme F# (une base de OCaml sous .NET), et Reason / ReScript.
- Documentation en français
- Guidelines
- Sur la programmation fonctionnelle
- Au sujet des expressions
- Cheatsheet
- Le système de build dune
- Sources de JaneStreet
- Sources de Mirage
Ce que j'ai moins apprécié
On ne peut pas suivre la step down rule (définir la fonction appelante au dessus de la fonction appelée) si j'ai bien compris<-- en fait si, avec `and`, voir la fonction `is_strike` ci-dessus- Devoir répéter le pattern pour chaque guarde `when`
- Des symbols un peu plus présents qu'en Haskell (`::` pour `:`, `@@` pour `$`, les `~` devant les paramètres nommés)
- Le `;;` pour finir une instruction dans le repl
Kata Bowling en Haskell
Pour explorer les ressemblances, j'ai fait le même kata en Haskell :
module Bowling (score, Roll(..)) where data Roll = Roll Int deriving (Eq) data Frame = Frame Int deriving (Eq) next (Frame n) = Frame (n + 1) score = score' $ Frame 1 score' f xs = case xs of [] -> 0 r1@(Roll x):r2@(Roll y):r3@(Roll z):rest | isLastFrame f -> x + y + z | isStrike r1 -> 10 + y + z + score' (next f) (r2:r3:rest) | isSpare r1 r2 -> 10 + z + score' (next f) (r3:rest) Roll x:Roll y:rest -> x + y + score' (next f) rest [_] -> error "Wrong number of rolls" where isStrike = (==) $ Roll 10 isSpare (Roll x) (Roll y) = 10 == x + y isLastFrame = (==) $ Frame 10
Sur cet exemple, les deux implémentations sont vraiment proches.
Le répo github est ici, la liste des commits montre le cheminement :
Conclusion
Je suis content d'avoir découvert OCaml, je pense en refaire plus tard, par exemple pour explorer l'orientation objet. Ou peut-être découvrir F# pour explorer encore un autre langage de ce type ?
Note : je ne suis un expert ni en OCaml, ni en Haskell. Je suis preneur d'avis pour améliorer tout ça.