(* TEST * expect *) (* HOAS to de Bruijn, by chak *) (* http://www.cse.unsw.edu.au/~chak/haskell/term-conv/ *) module Typeable = struct type 'a ty = | Int: int ty | String: string ty | List: 'a ty -> 'a list ty | Pair: ('a ty * 'b ty) -> ('a * 'b) ty | Fun: ('a ty * 'b ty) -> ('a -> 'b) ty type (_,_) eq = Eq : ('a,'a) eq exception CastFailure let rec check_eq : type t t'. t ty -> t' ty -> (t,t') eq = fun t t' -> match t, t' with | Int, Int -> Eq | String, String -> Eq | List t, List t' -> (match check_eq t t' with Eq -> Eq) | Pair (t1,t2), Pair (t1',t2') -> (match check_eq t1 t1', check_eq t2 t2' with Eq, Eq -> Eq) | Fun (t1,t2), Fun (t1',t2') -> (match check_eq t1 t1', check_eq t2 t2' with Eq, Eq -> Eq) | _ -> raise CastFailure let gcast : type t t'. t ty -> t' ty -> t -> t' = fun t t' x -> match check_eq t t' with Eq -> x end;; [%%expect{| module Typeable : sig type 'a ty = Int : int ty | String : string ty | List : 'a ty -> 'a list ty | Pair : ('a ty * 'b ty) -> ('a * 'b) ty | Fun : ('a ty * 'b ty) -> ('a -> 'b) ty type (_, _) eq = Eq : ('a, 'a) eq exception CastFailure val check_eq : 't ty -> ' t' ty -> ('t, ' t') eq val gcast : 't ty -> ' t' ty -> 't -> ' t' end |}];; module HOAS = struct open Typeable type _ term = | Tag : 't ty * int -> 't term | Con : 't -> 't term | Lam : 's ty * ('s term -> 't term) -> ('s -> 't) term | App : ('s -> 't) term * 's term -> 't term let rec intp : type t. t term -> t = function | Tag (_, ix) -> failwith "HOAS.intp" | Con v -> v | Lam (_, f) -> fun x -> intp (f (Con x)) | App (f, a) -> intp f (intp a) end;; [%%expect{| module HOAS : sig type _ term = Tag : 't Typeable.ty * int -> 't term | Con : 't -> 't term | Lam : 's Typeable.ty * ('s term -> 't term) -> ('s -> 't) term | App : ('s -> 't) term * 's term -> 't term val intp : 't term -> 't end |}];; module DeBruijn = struct type ('env,'t) ix = | ZeroIx : ('env * 't, 't) ix | SuccIx : ('env,'t) ix -> ('env * 's, 't) ix let rec to_int : type env t. (env,t) ix -> int = function | ZeroIx -> 0 | SuccIx n -> to_int n + 1 type ('env,'t) term = | Var : ('env,'t) ix -> ('env,'t) term | Con : 't -> ('env,'t) term | Lam : ('env * 's, 't) term -> ('env, 's -> 't) term | App : ('env, 's -> 't) term * ('env, 's) term -> ('env, 't) term type _ stack = | Empty : unit stack | Push : 'env stack * 't -> ('env * 't) stack let rec prj : type env t. (env,t) ix -> env stack -> t = fun i s -> match i, s with | ZeroIx, Push (s,v) -> v | SuccIx i, Push (s,_) -> prj i s let rec intp : type env t. (env,t) term -> env stack -> t = fun t s -> match t with | Var ix -> prj ix s | Con v -> v | Lam b -> fun x -> intp b (Push (s, x)) | App(f,a) -> intp f s (intp a s) end;; [%%expect{| module DeBruijn : sig type ('env, 't) ix = ZeroIx : ('env * 't, 't) ix | SuccIx : ('env, 't) ix -> ('env * 's, 't) ix val to_int : ('env, 't) ix -> int type ('env, 't) term = Var : ('env, 't) ix -> ('env, 't) term | Con : 't -> ('env, 't) term | Lam : ('env * 's, 't) term -> ('env, 's -> 't) term | App : ('env, 's -> 't) term * ('env, 's) term -> ('env, 't) term type _ stack = Empty : unit stack | Push : 'env stack * 't -> ('env * 't) stack val prj : ('env, 't) ix -> 'env stack -> 't val intp : ('env, 't) term -> 'env stack -> 't end |}];; module Convert = struct type (_,_) layout = | EmptyLayout : ('env, unit) layout | PushLayout : 't Typeable.ty * ('env,'env') layout * ('env,'t) DeBruijn.ix -> ('env,'env' * 't) layout let rec size : type env env'. (env,env') layout -> int = function | EmptyLayout -> 0 | PushLayout (_, lyt, _) -> size lyt + 1 let rec inc : type env env'. (env,env') layout -> (env * 't, env') layout = function | EmptyLayout -> EmptyLayout | PushLayout (t, lyt, ix) -> PushLayout (t, inc lyt, DeBruijn.SuccIx ix) let rec prj : type env env' t. t Typeable.ty -> int -> (env,env') layout -> (env,t) DeBruijn.ix = fun t n -> function | EmptyLayout -> failwith "Convert.prj: internal error" | PushLayout (t', l, ix) -> if n = 0 then match Typeable.check_eq t t' with Typeable.Eq -> ix else prj t (n-1) l let rec cvt : type env t. (env,env) layout -> t HOAS.term -> (env,t) DeBruijn.term = fun lyt -> function | HOAS.Tag (t, sz) -> DeBruijn.Var (prj t (size lyt - sz -1) lyt) | HOAS.Con v -> DeBruijn.Con v | HOAS.Lam (t, f) -> let lyt' = PushLayout (t, inc lyt, DeBruijn.ZeroIx) in DeBruijn.Lam (cvt lyt' (f (HOAS.Tag (t, size lyt)))) | HOAS.App (f, a) -> DeBruijn.App (cvt lyt f, cvt lyt a) let convert t = cvt EmptyLayout t end;; [%%expect{| module Convert : sig type (_, _) layout = EmptyLayout : ('env, unit) layout | PushLayout : 't Typeable.ty * ('env, 'env') layout * ('env, 't) DeBruijn.ix -> ('env, 'env' * 't) layout val size : ('env, 'env') layout -> int val inc : ('env, 'env') layout -> ('env * 't, 'env') layout val prj : 't Typeable.ty -> int -> ('env, 'env') layout -> ('env, 't) DeBruijn.ix val cvt : ('env, 'env) layout -> 't HOAS.term -> ('env, 't) DeBruijn.term val convert : 'a HOAS.term -> (unit, 'a) DeBruijn.term end |}];; module Main = struct open HOAS let i t = Lam (t, fun x -> x) let zero t = Lam (Typeable.Fun(t,t), fun f -> Lam(t, fun x -> x)) let one t = Lam (Typeable.Fun(t,t), fun f -> Lam(t, fun x -> App (f, x))) let two t = Lam (Typeable.Fun(t,t), fun f -> Lam(t, fun x -> App (f, App (f, x)))) let three t = Lam (Typeable.Fun(t,t), fun f -> Lam(t, fun x -> App (f, App (f, App (f, x))))) let plus t = let t1 = Typeable.Fun(t,t) in let t2 = Typeable.Fun(t1,t1) in Lam (t2, fun m -> Lam (t2, fun n -> Lam (t1, fun f -> Lam(t, fun x -> App(App(m,f), App(App(n,f),x)))))) let plus_2_3 t = App (App (plus t, two t), three t) open Convert let i' = convert (i Typeable.Int) let plus_2_3' = convert (plus_2_3 Typeable.Int) let eval_plus_2_3' = DeBruijn.intp plus_2_3' DeBruijn.Empty succ 0 end;; [%%expect{| module Main : sig val i : 'a Typeable.ty -> ('a -> 'a) HOAS.term val zero : 'a Typeable.ty -> (('a -> 'a) -> 'a -> 'a) HOAS.term val one : 'a Typeable.ty -> (('a -> 'a) -> 'a -> 'a) HOAS.term val two : 'a Typeable.ty -> (('a -> 'a) -> 'a -> 'a) HOAS.term val three : 'a Typeable.ty -> (('a -> 'a) -> 'a -> 'a) HOAS.term val plus : 'a Typeable.ty -> ((('a -> 'a) -> 'a -> 'a) -> (('a -> 'a) -> 'a -> 'a) -> ('a -> 'a) -> 'a -> 'a) HOAS.term val plus_2_3 : 'a Typeable.ty -> (('a -> 'a) -> 'a -> 'a) HOAS.term val i' : (unit, int -> int) DeBruijn.term val plus_2_3' : (unit, (int -> int) -> int -> int) DeBruijn.term val eval_plus_2_3' : int end |}];;