We need to activate autolifting for this:
(mode autolift) (mode unfold) |
We start with a generic representation:
type 'a gen = | Pair of ('a gen * 'a gen) | Value of 'a | Unit |
We define a map function:
let rec gen_map f x = match x with | Pair(u,v) -> Pair(gen_map f u, gen_map f v) | Value x -> Value (f x) | Unit -> Unit |
Then we define lists:
type 'a list = | Nil | Cons of ('a * 'a list) |
Lists are a specialization of the generic representation:
type ornament 'a gen_list : 'a gen => 'a list with | Unit => Nil | Pair t => Cons t when t : ('a gen_elem * 'a gen_list) | Value x => ~ and 'a gen_elem : 'a gen => 'a with | Value x => x | Unit => ~ | Pair t => ~ when t : ('a gen_elem * 'a gen_list) |
Then we can derive a map function:
let map_list = lifting gen_map : ('a -> 'b) -> 'a gen_list -> 'b gen_list |
We get this result, with an intermediate function:
let rec map_list f x = match x with | Cons (u, v) -> Cons (gen_map_auto1 f u, map_list f v) | Nil -> Nil and gen_map_auto1 f x = f x |
We can do the same with trees:
type 'a tree = | Leaf | Node of ('a * ('a tree * 'a tree)) |
type ornament 'a gen_tree : 'a gen => 'a tree with | Unit => Leaf | Pair t => Node t when t : ('a gen_value * 'a gen_treepair) | Value x => ~ and 'a gen_value : 'a gen => 'a with | Value x => x | Unit => ~ | Pair t => ~ when t : ('a gen_tree * 'a gen_tree) and 'a gen_treepair : 'a gen => 'a tree * 'a tree with | Unit => ~ | Pair t => t when t : ('a gen_tree * 'a gen_tree) | Value x => ~ |
let map_tree = lifting gen_map : ('a -> 'b) -> 'a gen_tree -> 'b gen_tree |
We get the expected result:
let rec map_tree f x = match x with | Node (u, v) -> Node (gen_map_auto3 f u, gen_map_auto2 f v) | Leaf -> Leaf and gen_map_auto2 f x = match x with | (u, v) -> (map_tree f u, map_tree f v) and gen_map_auto3 f x = f x |