A tutorial for Ocaml-templates ****************************** François Maurel =============== 1 Introduction to Ocaml-templates *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ocaml-templates is a tool to automatically generate code in the Objective Caml language (1) from type informations. 1.1 Distribution ================= The official web-page is http://www.pps.jussieu.fr/~maurel/programmation/. The distribution is open source has stated in the LICENSE file. 1.2 Authors ============ The principal author is François Maurel. Some code in several templates has been written by Jean-Baptiste Tristan. 2 Using a template *=*=*=*=*=*=*=*=*=* 1. Let us study a program one may write with templates. This programs first defines a type for birds and characteristics for these birds (size and predator). Then a type of tree is defined and bird are put on leaves. Some code is generated `random_*' and `map_*' and then used. << type eagle_type : Random = Royal | Golden;; type size : Random = Big | Small;; type predator : Random = Predator | Food;; type 'a bird : Random : Map = Eagle of eagle_type | Seagull of 'a * int | Kestrel of 'a | Chickens of 'a list;; type 'a tree : Random : Map = Leaf of 'a | Node / Random(proba={0.3}) of 'a tree * 'a tree;; let change_size = function Big -> Small |Small -> Big;; let change_predator = function Predator -> Food |Food -> Predator;; let t1 = random_tree (random_bird random_size) ();; let t1' = map_tree (map_bird change_size) t1;; let t2 = random_tree (random_bird random_predator) ();; let t2' = map_tree (map_bird change_predator) t2;; >> 2. This program is automatically translated into the following one: << type eagle_type = Royal | Golden >> << let rec random_eagle_type () = match Random.float 1. with x when x >= 0.5 -> Royal | _ -> Golden >> << type size = Big | Small >> << let rec random_size () = match Random.float 1. with x when x >= 0.5 -> Big | _ -> Small >> << type predator = Predator | Food >> << let rec random_predator () = match Random.float 1. with x when x >= 0.5 -> Predator | _ -> Food >> << type 'a bird = Eagle of eagle_type | Seagull of 'a * int | Kestrel of 'a | Chickens of 'a list >> << let rec map_bird __map_a = function Eagle a_1 -> Eagle a_1 | Seagull (a_1, a_2) -> Seagull (__map_a a_1, a_2) | Kestrel a_1 -> Kestrel (__map_a a_1) | Chickens a_1 -> Chickens (List.map __map_a a_1) let rec random_bird = let rec cree_liste n f () = if n = 0 then [] else f () :: cree_liste (n - 1) f () in fun random_a () -> match Random.float 1. with x when x >= 0.75 -> Eagle (random_eagle_type ()) | x when x >= 0.5 -> Seagull (random_a (), Random.int 100) | x when x >= 0.25 -> Kestrel (random_a ()) | _ -> Chickens (cree_liste (Random.int 5) random_a ()) >> << type 'a tree = Leaf of 'a | Node of 'a tree * 'a tree >> << let rec map_tree __map_a = function Leaf a_1 -> Leaf (__map_a a_1) | Node (a_1, a_2) -> Node (map_tree __map_a a_1, map_tree __map_a a_2) let rec random_tree random_a () = match Random.float 0.8 with x when x >= 0.3 -> Leaf (random_a ()) | _ -> Node (random_tree random_a (), random_tree random_a ()) >> << let change_size = function Big -> Small | Small -> Big let change_predator = function Predator -> Food | Food -> Predator let t1 = random_tree (random_bird random_size) () let t1' = map_tree (map_bird change_size) t1 let t2 = random_tree (random_bird random_predator) () let t2' = map_tree (map_bird change_predator) t2 >> 3. We may describe this code 1. << type eagle_type : Random = Royal | Golden;; >> Defines a type `eagle_type' and generates a function called `random_eagle_type' which creates an `eagle_type' by random. 2. << type size : Random = Big | Small;; >> << type predator : Random = Predator | Food;; >> Defines two types and random functions for them. 3. << type 'a bird : Random : Map = Eagle of eagle_type | Seagull of 'a * int | Kestrel of 'a | Chickens of 'a list;; >> Defines a parametric type with two functions : a random function and a map function. Both of them take, as a first argument, a parameter for a random or map function for the type parameter 'a. 4. << type 'a tree : Random : Map = Leaf of 'a | Node / Random(proba={0.3}) of 'a tree * 'a tree;; >> Similar construction. Furthermore, the template `Random' uses an option named `proba' which takes a float and associates a probability to the constructor to appear in `random_tree'. 5. << let change_size = function Big -> Small |Small -> Big;; >> << let change_predator = function Predator -> Food |Food -> Predator;; >> These functions will be parameters for generated functions `random_*' and `map_*'. 6. << let t1 = random_tree (random_bird random_size) ();; let t1' = map_tree (map_bird change_size) t1;; >> << let t2 = random_tree (random_bird random_predator) ();; let t2' = map_tree (map_bird change_predator) t2;; >> Some use of the generated functions... 4. The types infered by `ocaml -i -pp ocamltsp4 test.ml' << type eagle_type = Royal | Golden val random_eagle_type : unit -> eagle_type type size = Big | Small val random_size : unit -> size type predator = Predator | Food val random_predator : unit -> predator type 'a bird = Eagle of eagle_type | Seagull of 'a * int | Kestrel of 'a | Chickens of 'a list val map_bird : ('a -> 'b) -> 'a bird -> 'b bird val random_bird : (unit -> 'a) -> unit -> 'a bird type 'a tree = Leaf of 'a | Node of 'a tree * 'a tree val map_tree : ('a -> 'b) -> 'a tree -> 'b tree val random_tree : (unit -> 'a) -> unit -> 'a tree val change_size : size -> size val change_predator : predator -> predator val t1 : size bird tree val t1' : size bird tree val t2 : predator bird tree val t2' : predator bird tree >> 5. A typical result << val t1 : size bird tree = Node (Leaf (Seagull (Big, 56)), Leaf (Kestrel Big)) val t1' : size bird tree = Node (Leaf (Seagull (Small, 56)), Leaf (Kestrel Small)) val t2 : predator bird tree = Node (Leaf (Kestrel Predator), Node (Leaf (Seagull (Predator, 83)), Leaf (Chickens [Food; Predator; Food; Food]))) val t2' : predator bird tree = Node (Leaf (Kestrel Food), Node (Leaf (Seagull (Food, 83)), Leaf (Chickens [Predator; Food; Predator; Predator]))) >> In this example, we see that for the constructor `Chickens', the `map_bird' automatically uses a `List.map'. 3 Some templates *=*=*=*=*=*=*=*=* This section presents some already defined templates. 1. `Compare' 2. `Copy' 3. `Default' 4. `Length' 5. `Map' 6. `Param_Iter' 7. `Print_Aml' 8. `Print' 9. `Projection' 10. `Random' 11. `Read_Aml' 12. `String_Of' 13. `Tdpe' ------------------------------------------------------------------------ ----- |`Template' |S|R|App|Share|sort |Description | ------------------------------------------------------------------------ ----- |`Compare' | | | | |*->*-> int |Compare two | | | | | | | |types | |`Copy' | | | | |*->* |Duplicates a | | | | | | | |structures | |`Default' | | | | |`unit'->* |Creates a | | | | | | | |default value | | | | | | | |of a given | | | | | | | |type | |`Length' | | | | |alpha *-> int |Counts the | | | | | | | |number of | | | | | | | |alpha in a | | | | | | | |type | |`Map' | | | | |(alpha *->beta)->alpha *->beta *|Maps a | | | | | | | |function | |`Print_Aml' | | | | |*-> unit |Pretty-prints | | | | | | | |à la ML | |`Print' | | | | |*-> unit |Gives a printf| | | | | | | |function | |`Projection'| | | | |*->*' |Sends a type | | | | | | | |onto another | | | | | | | |one | |`Random' | | | | |`unit'->* |Creates a | | | | | | | |random value | | | | | | | |of a given | | | | | | | |type | |`Read_Aml' | | | | |`string'->* |Reads à la ML | |`String_Of' | | | | |*-> string | | |`Tdpe' | | | | |(*-> lambda,lambda->*) |Uncompiles | | | | | | | |polymorphic | | | | | | | |functions | ------------------------------------------------------------------------ ----- ----------------------------------- (1) http://caml.inria.fr ----------------------------------------------------------------------- This document was translated from LaTeX by HeVeA (http://pauillac.inria.fr/~maranget/hevea/index.html).