La soluce repose tout simplement sur la fainéantise. (j'aime bien dire ça, ça sous-entend que c'est évident, alors que si on m'avait pas mis sur la voie, je serais encore en train de chercher).
Code :
- (* arbre de départ *)
- type 'a ltree = LLeaf of 'a | LNode of 'a ltree * 'a ltree
- (* arbre d'arrivée *)
- (* solution à parent lazy, enfants lazy ou tout le monde lazy possible *)
- type 'a rtree = RRoot of 'a rtree | RNode of 'a rtree * 'a rtree * 'a rtree Lazy.t | RLeaf of 'a * 'a rtree Lazy.t
- let lexemple =
- LNode(
- LNode(
- LNode(LLeaf(20), LLeaf(10)),
- LNode(LLeaf(10), LNode(LLeaf(14), LLeaf(10)))),
- LNode(LLeaf(30), LLeaf(53))
- )
- let convert t =
- let rec root = lazy(RRoot(tree t))
- and tree t' = go root t'
- and go pn = function
- | LLeaf(v) -> RLeaf(v, pn)
- | LNode(f, s) ->
- let rec top = lazy (RNode(lson f, rson s, pn)) (* l'image du noeud *)
- and lson f' = go top f' (* l'image de son fils gauche *)
- and rson s' = go top s' (* l'image de son fils droit *)
- in Lazy.force top
- in Lazy.force root
- (* explosons l'affichage du toplevel ! *)
- let r = convert lexemple
- (*
- comme marqué dans
- http://caml.inria.fr/ocaml/htmlman [...] s:localdef (dernière ligne)
- Caml sait pas faire grand'chose en récursif indirect pour les valeur non-fonctionelles.
- en Haskell, la notation est plus proche de (pour les premières lignes) :
- let convert t =
- let rec root = lazy(RRoot(tree))
- and tree = go root t
- ben tant pis.
- *)
|
Pour ceux qui ne conaissent pas le lazy, c'est une expression stockée sous forme non évaluée.
notation :
)
elle ne sera évaluée que si c'est nécessaire (par Lazy.force).
est en fait le type
(une fonction qui prend l'unité () en paramètre et qui renvoie un 'a)
est l'équivalent de
passer l'unité en paramètre à la fonction (donc l'évaluer).
et
est transformé syntaxiquement (grace à camlp4) en
(fun () -> <expression> ) |
Voilou.
Message édité par nraynaud le 27-02-2003 à 22:53:01