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 language1 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         a *® int Counts the number of a in a type
Map         (a *®b)®a *®b * 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         (*® l,l®*) Uncompiles polymorphic functions


1
http://caml.inria.fr

This document was translated from LATEX by HEVEA.