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
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.
Top comments (0)