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 :
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.
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, avecand
, voir la fonctionis_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.