type _ typ = | Int : int -> int typ | Unit : unit typ let typ_to_string : type a. a typ -> string = function | Int n -> Printf.sprintf "%d" n | Unit -> "()" type (_, _) binop = | Add : (int, int) binop | Sub : (int, int) binop | Mul : (int, int) binop | Div : (int, int) binop let binop_to_string : type a b. (a, b) binop -> string = function | Add -> "+" | Sub -> "-" | Mul -> "*" | Div -> "/" type _ t = | Value : 'a typ -> 'a t | Binop : 'a t * ('a, 'b) binop * 'a t -> 'b t | Set_binop_pre : ('a, 'b) binop * int t -> unit t let value v = Value v let binop left op right = Binop (left, op, right) let set_binop_pre op pre = Set_binop_pre (op, pre) (* print ast LISP style. *) let print ast = let pr = Printf.printf in let pv v = pr "%s" @@ typ_to_string v in let rec aux : type a. a t -> unit = function | Value n -> pv n | Binop (left, op, right) -> begin pr "(%s " @@ binop_to_string op; aux left; pr " "; aux right; pr ")"; end | Set_binop_pre (op, pre) -> pr "(set_pre %s " (binop_to_string op); aux pre; pr ")" in aux ast; pr "\n"