type var = (* unique name *) int * (int * term) option * (*level*) int
and term =
| Tvar of var
| Tapp of term * term
| Tlam of int * term
;;
let zero = Tvar 1010;;
let dummy = Tvar 333;;
(* mk_app & subst implementano la beta *)
let rec mk_app t1 t2 = match t1 with
| Tlam(v, t1') -> subst v t2 t1'
| _ -> Tapp(t1, t2, false)
and subst v tv =
let rec aux = function
| Tapp(t1, t2, _) -> mk_app (aux t1) (aux t2)
| Tvar v' as t -> if v = v' then tv else t
| Tlam(v', t') as t -> if v = v' then t else Tlam(v', aux t')
in aux
;;
(* PARSING AND PRINTING *)
let parse =
let rec minus1 = function
| Tvar n -> Tvar (n-1)
| Tapp(t1, t2, b) -> Tapp(minus1 t1, minus1 t2, b)
| Tlam(n, t) -> Tlam(n-1, minus1 t)
(* in let open Parser *)
in let rec myterm_of_term = function
| Parser.Var n -> Tvar n
| Parser.App(t1, t2) -> (*Tapp(myterm_of_term t1, myterm_of_term t2) WARNING! BETA DOWN HERE! *)
mk_app (myterm_of_term t1) (myterm_of_term t2)
| Parser.Lam(t) -> minus1 (Tlam(0, myterm_of_term t))
in fun strs -> (
let (tms, free) = Parser.parse_many strs
in List.map myterm_of_term tms
)
;;
(* PRETTY PRINTING *)
open Console;;
let fancy_of_term t =
let rec string_of_term =
let free = ["a"; "b"; "c"; "d"; "e"; "f"; "g"] in
let bound = ["x"; "y"; "z"; "w"; "q"; "x1"; "x2"] in
let string_of_int' n = if n >= 0 then "free" ^ string_of_int n else "bound" ^ string_of_int n in
let rec string_of_var t =
if Tvar t = dummy then "_" else if Tvar t = zero then "ZZ" else match t with
| n -> string_of_int' n
and string_of_term_w_pars = function
| Tvar v -> string_of_var v
| Tapp(t1, t2, _) -> "(" ^ (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2) ^ ")"
| Tlam(_,_) as t -> "(" ^ (string_of_term_no_pars_lam t) ^ ")"
and string_of_term_no_pars_app = function
| Tapp(t1, t2,_) -> (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2)
| _ as t -> string_of_term_w_pars t
and string_of_term_no_pars_lam = function
| Tlam(v, t) -> "λ" ^ (string_of_int' v) ^ ". " ^ (string_of_term_no_pars_lam t)
| _ as t -> string_of_term_no_pars t
and string_of_term_no_pars = function
| Tlam(_, _) as t -> string_of_term_no_pars_lam t
| _ as t -> string_of_term_no_pars_app t
in string_of_term_no_pars
in let rec html_of_term =
let free = ["a"; "b"; "c"; "d"; "e"; "f"; "g"; "h"; "i"; "j"] in
let bound = ["x"; "y"; "z"; "w"; "q"] in
let string_of_int' n = if n >= 0 then List.nth free (n) else List.nth bound (-n-1) in
let rec string_of_var t =
if Tvar t = dummy then "#" else if Tvar t = zero then "Z" else string_of_int' t
and string_of_term_w_pars = function
| Tvar v -> string_of_var v
| Tapp(t1, t2,_) -> "(" ^ (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2) ^ ")"
| Tlam(_,_) as t -> "(" ^ (string_of_term_no_pars_lam t) ^ ")"
and string_of_term_no_pars_app = function
| Tapp(t1, t2,_) -> (string_of_term_no_pars_app t1) ^ " " ^ (string_of_term_w_pars t2)
| _ as t -> string_of_term_w_pars t
and string_of_term_no_pars_lam = function
| Tlam(v, t) -> "λ" ^ (string_of_int' v) ^ ". " ^ (string_of_term_no_pars_lam t)
| _ as t -> string_of_term_no_pars t
and string_of_term_no_pars = function
| Tlam(_, _) as t -> string_of_term_no_pars_lam t
| _ as t -> string_of_term_no_pars_app t
in string_of_term_no_pars
in
string_of_term t / "html_of_term t"
;;
let fancy_of_nf t: Console.fancyobj =
let rec print ?(l=[]) =
function
`Var n -> Util.Vars.print_name l n
| `N n -> string_of_int n
| `Match(t,bs_lift,bs,args) ->
"([" ^ print ~l (t :> Num.nf) ^
" ? " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " => " ^ print ~l (Num.lift bs_lift t)) !bs) ^ "] " ^
String.concat " " (List.map (print ~l) args) ^ ")"
| `I(n,args) -> "(" ^ Util.Vars.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print ~l) args)) ^ ")"
| `Lam(_,nf) ->
let name = Util.Vars.string_of_var (List.length l) in
"" ^ name ^ "." ^ print ~l:(name::l) (nf : Num.nf)
(* in let rec print_html ?(l=[]) =
function
`Var n -> Lambda3.print_name l n
| `N n -> string_of_int n
| `Match(t,bs_lift,bs,args) ->
"(match " ^ print_html ~l (t :> Lambda3.nf) ^
" with " ^ String.concat " | " (List.map (fun (n,t) -> string_of_int n ^ " ⇒ " ^ print_html ~l (Lambda3.lift bs_lift t)) !bs) ^ "..." (* Attenzion non sto stampando gli argomenti applicati! Perche' non ce ne sono mai *)
| `I(n,args) -> "(" ^ Lambda3.print_name l n ^ " " ^ String.concat " " (Listx.to_list (Listx.map (print_html ~l) args)) ^ ")"
| `Lam nf ->
let name = Lambda3.string_of_var (List.length l) in
"λ" ^ name ^ ". " ^ print_html ~l:(name::l) (nf : Lambda3.nf) *)
in
print t / print t
;;
let print_term t = print_endline (fancy_of_term t :> Console.fancyobj);;
(* *)
let varcount = ref 11;;
let freshvar () = (
varcount := (!varcount + 1);
!varcount
);;
(* magic ["x (x x x)"; "x (y. y x)"; "x x (y. y y (x x y))"] ;; *)
(* magic ["((x x) (x. x))";"x x"];; *)
let alive (_, _, n) = n;;
let rec setalive c = function
| Tvar(a,b,_) as v -> if v <> zero && v <> dummy then Tvar(a,b,c) else v
| Tapp(a,b) -> Tapp(setalive c a, setalive c b)
| Tlam(n, t) -> Tlam(n, setalive c t)
;;
let mk_vars t lev =
let rec aux n =
if n = 0
then []
else Tvar(0, Some(n, t), lev) :: (aux (n-1))
in aux
;;
let mk_apps t ts = List.fold_right (fun x y -> mk_app y x) (List.rev ts) t;; (* which FOLD? FIXME *)
let compute_special_k tms =
let rec aux k t = match t with
| Tvar _ -> 0
| Tapp(t1,t2) -> Pervasives.max (aux 0 t1) (aux 0 t2)
| Tlam(v,t) -> Pervasives.max (k+1) (aux (k + 1) t)
in List.fold_left (fun b a -> Pervasives.max (aux 0 a) b) 0 tms
;;
let compute_special_h tms =
let rec eat_lam = function
| Tlam(_,t) -> eat_lam t
| _ as t -> t
in
let rec aux t = match t with
| Tvar _ -> 0
| Tapp(t1,t2) -> Pervasives.max (aux t1) (aux t2)
| Tlam(v,t) -> 1 + (aux (eat_lam t))
in 1 + List.fold_left (fun b a -> Pervasives.max (aux a) b) 0 tms
;;
(* funzione di traduzione brutta & cattiva *)
let translate k =
let rec aux = function
| Tlam _ -> assert false
| Tvar _ as v -> v
| Tapp(t1, t2) ->
let v = hd t1 in
let a = alive v in
let t1' = aux t1 in
let t2' = if a = 0
then t2
else mk_apps t2 ((List.rev (mk_vars t1' (a-1) k)) @ [zero])
in Tapp(t1', aux t2')
in aux
;;
(* sostituisce gli argomenti dummy (delle variabili morte) con 'dummy' *)
let rec dummize = function
| Tlam _ -> assert false
| Tvar (a,Some(b,t), c) -> Tvar(a, Some (b, dummize t), c)
| Tvar _ as v -> v
| Tapp(t1, t2) ->
if alive (hd t1) = 0
then Tapp(dummize t1, dummy)
else Tapp(dummize t1, dummize t2)
;;
(* lista di sottotermini applicativi *)
let rec subterms = function
| Tlam _ -> assert false
| Tvar _ as v -> [v]
| Tapp(t1, t2) -> Tapp(t1, t2) :: ((subterms t1) @ (subterms t2))
;;
(* filtra dai sottotermini le variabili *)
let rec vars subs = List.filter (function Tvar _ -> true | _ -> false) subs;;
let rec stupid_uniq = function
| [] -> []
| x::xs -> if List.mem x xs then (stupid_uniq xs) else x::(stupid_uniq xs)
;;
let stupid_compare a b =
let rec size = function
| Tvar(_,None,_) -> 0
| Tvar(_,Some(_,t),_) -> 1 + size t
| Tapp(t1,t2) -> 1 + size t1 + size t2
| Tlam _ -> assert false
in compare (size a) (size b)
;;
let stupid_sort_uniq l = stupid_uniq (List.sort stupid_compare l);;
(* crea i match ricorsivamente.
- k e' lo special-K
- subs e' l'insieme dei sottotermini
TODO: riscrivere la funzione per evitare/ottimizzare la ricorsione
*)
let crea_match k subs (acc : (term * Lambda3.nf) list) : term -> Lambda3.nf =
let req t = try List.assoc t acc with Not_found -> `Var 9999 in
let aux t1 = (
if t1 = dummy then `Var 99999 else
(* let _ = print_term t1 in *)
let cont = List.filter (fun t2 -> List.mem (Tapp(t1,t2)) subs) subs
in if cont = [] then
try `N (Lambda3.index_of t1 subs) with Not_found -> `Var 999 (* variabile dummy qui *) else
let a = alive (hd t1) in
if a = 0 then `Lam (req (Tapp(t1, dummy)))
else (
let vars = (List.rev (mk_vars t1 (a-1) k)) @ [zero]
(* in let _ = print_endline (String.concat " " (List.map string_of_term vars))
in let _ = print_term (mk_apps dummy vars) *)
in let vars = List.map req vars
in let vars = List.map (Lambda3.lift 1) vars (* forse lift non necessario *)
in let vars = Listx.from_list vars
in let body = `I(0, vars)
in let branches = List.map (fun t2 -> (Lambda3.index_of t2 subs, req (Tapp(t1, t2)))) cont
in let bs = ref(branches)
in let lift = 1
in let args = []
in `Lam (`Match(body, lift, bs, args))
)
) in aux
;;
let mk_zeros k =
let rec aux n prev =
if n = 0 then [zero]
else let prev = aux (n-1) prev in let x = mk_app (List.hd prev) dummy in x :: prev
in aux (k+1) []
;;
let is_scott_n t n =
let open Lambda3 in let open Pure in
let rec aux n = function
| L (L (A (V 1, L (V 0)))) -> n = 0
| L (L (A (V 0, t))) -> aux (n-1) t
| _ -> assert false
in aux n t
;;
(* do the magic *)
let magic strings k h = (
let tms = parse strings
in let tms = List.map (fun x -> Tapp(x, zero)) tms
in let tms' = List.map (setalive h) tms
in let tms' = List.map (translate k) tms'
in let tms' = List.map dummize tms'
(* in let bullet = ">" / "•" *)
(* in let progress s = print_endline (bullet ^^ fancy_of_string s) *)
in let progress = print_h1
in let _ = progress "traduzione completata"
(* in let _ = List.map print_term tms' *)
in let _ = progress "ordino i sottotermini"
in let subs = List.concat (List.map subterms tms')
in let subs = stupid_sort_uniq subs
(* metti gli zeri in testa, perche' vanno calcolati per primi *)
in let zeros = mk_zeros k
in let subs = (List.filter (fun t -> not (List.mem t zeros)) subs) @ (List.rev zeros)
in let _ = progress ("sottotermini generati: " ^ string_of_int (List.length subs))
in let vars = vars subs
(* in let _ = List.iter print_term subs *)
(* in let _ = 0/0 *)
in let fv = List.filter (function Tvar(_, None, _) as v -> v <> dummy | _ -> false) vars
(* in let _ = print_string ("> free vars: " ^ String.concat ", " (List.map (string_of_term) fv)) *)
in let _ = progress "sto creando i match"
(* in let sigma = List.map (fun x -> x, crea_match k subs x) fv *)
in let f t acc = let res = crea_match k subs acc t in (t,res)::acc
in let acc = List.fold_right f subs []
in let sigma = List.filter (fun (t,res) -> List.mem t fv) acc
in let _ = progress "match creati"
in let _ = List.iter (fun (x,y) -> print_endline (fancy_of_term x ^^ (" : " / " ↦ ") ^^ fancy_of_nf y)) sigma
in let _ = progress "controllo di purezza";
in let open Lambda3
in let ps, _ = Lambda3.parse' strings
in let ps = List.map (fun x -> Lambda3.mk_app x (`Var 1010)) ps
in let ps = List.map (fun t -> ToScott.t_of_nf (t :> nf)) ps
in let sigma = List.map (
function (Tvar(n,_,_), inst) -> n, ToScott.t_of_nf inst | _ -> assert false
) sigma
in let ps =
List.fold_left (fun ps (x,inst) -> List.map (Pure.subst false x inst) ps) ps sigma
in let _ = List.iteri (fun i n ->
(* print_string_endline ((string_of_int i) ^ ":: " ^ (Pure.print (Pure.whd n))); *)
(* assert (Pure.whd n = Scott.mk_n (Lambda3.index_of (List.nth tms' i) subs))) ps *)
assert (is_scott_n (Pure.whd n) (Lambda3.index_of (List.nth tms' i) subs))) ps
in let _ = progress "fatto." in ()
);;
let do_everything tms =
let tms' = parse tms in
let k = compute_special_k tms' in
let h = compute_special_h tms' in
(* let _ = print_string_endline (string_of_int h) in *)
magic tms k h
;;
let _ =
let tms = ["a a"; "a b"; "b a"; "b (x. y.x y a)"] in
(* 1 2 *)
(* let tms = ["x c" ; "b (x c d e)"; "b"] in *)
(* 0 1 *)
(* let tms = ["x x x"] in *)
let tms' = parse tms in
let k = compute_special_k tms' in
let h = compute_special_h tms' in
(* let _ = print_string_endline (string_of_int h) in *)
magic tms k h
;;
(* type var' = (* unique name *) int * (int * term') option * (*dead*) bool option
and term' =
| Tvar' of var'
| Tapp' of term' * term' * (* active *) bool
| Tlam' of int * term'
;;
let rec iter mustapply =
let aux = function
| Tvar'(n, Some(m,t), b) -> Tvar(n, Some(m, aux t), b)
| Tvar' _ as v -> v
| Tapp'(t1, t2, b) -> if b &&
in aux
;; *)