From 50d592f09cf6c6226c53a054cd729df475c032d7 Mon Sep 17 00:00:00 2001 From: Guillermo Ramos Date: Wed, 22 Jul 2015 02:09:23 +0200 Subject: 21/07/15 --- code/krivine.ml | 250 ++++++++++++++++++++++++++ code/zam.ml | 546 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 796 insertions(+) create mode 100644 code/krivine.ml create mode 100644 code/zam.ml (limited to 'code') diff --git a/code/krivine.ml b/code/krivine.ml new file mode 100644 index 0000000..dfbdd4a --- /dev/null +++ b/code/krivine.ml @@ -0,0 +1,250 @@ +(*********************************************) +(* (Extended) Krivine Machine implementation *) +(* *) +(* Guillermo Ramos Gutiérrez (2015) *) +(*********************************************) + + +(*********) +(* Utils *) +(*********) +let print_with f x = print_endline (f x) +let concat_with sep f xs = String.concat sep (List.map f xs) + +let rec find_idx_exn x = function + | [] -> raise Not_found + | (y::ys) -> if x = y then 0 else 1 + find_idx_exn x ys + +let rec map_rev f xs = + let rec iter acc = function + | [] -> acc + | (x::xs) -> iter (f x :: acc) xs in + iter [] xs + +type symbol = string * int +let show_symbol (s, _) = s +let symbol : string -> symbol = + let id = ref 0 in + let gensym c : symbol = + let newid = !id in + id := !id + 1; + (c, newid) + in + gensym + + +(**************************************) +(* (Extended) Untyped Lambda Calculus *) +(**************************************) +module Lambda = struct + type t = Var of symbol | App of t * t | Abs of symbol * t + | If of t * t * t | True | False + | Constr of t constr | Case of t * (symbol constr * t) list + | Fix of symbol * t + and 'a constr = symbol * 'a list + + let rec show m = + let show_branch ((x, args), m) = + "(" ^ show_symbol x ^ "(" ^ concat_with "," show_symbol args ^ ") → " + ^ show m ^ ")" in + match m with + | Var x -> show_symbol x + | App (m1, m2) -> "(" ^ show m1 ^ " " ^ show m2 ^ ")" + | Abs (x, m) -> "(λ" ^ show_symbol x ^ "." ^ show m ^ ")" + | If (m1, m2, m3) -> "if " ^ show m1 + ^ " then " ^ show m2 + ^ " else " ^ show m3 + | True -> "True" | False -> "False" + | Constr (x, ms) -> show_symbol x ^ "(" ^ concat_with ", " show ms ^ ")" + | Case (m, bs) -> "(case " ^ show m ^ " of " + ^ concat_with " " show_branch bs ^ ")" + | Fix (x, m) -> "fix(λ" ^ show_symbol x ^ "." ^ show m ^ ")" + let print = print_with show + + (* Constants *) + let none = symbol "None" + let some = symbol "Some" + + (* Peano arithmetic *) + let z = symbol "z" + let s = symbol "s" + + let rec peano_add n x = + if n == 0 then x else peano_add (n-1) (Constr (s, [x])) + + let peano_of_int ?(base=Constr (z, [])) n = peano_add n base + + (* Examples *) + let m1 = + let x = symbol "x" in + let y = symbol "y" in + let z = symbol "z" in + App (Abs (x, Var x), App (Abs (y, Var y), Abs (z, Var z))) + + let plus = + let m = symbol "m" in + let n = symbol "n" in + let f = symbol "f" in + let x = symbol "x" in + Abs (m, Abs (n, Abs (f, Abs (x, App (App (Var m, Var f), + App (App (Var n, Var f), Var x)))))) + + let nested_if = + If (True, If (False, False, True), False) + + (* s((λx.x) z) *) + let constr_test = + let x = symbol "x" in + peano_of_int ~base:(App (Abs (x, Var x), Constr (z, []))) 1 + + (* (λc. case c of (Some(x) → x) (None → c)) Some(s(z))) *) + let case_some = + let c = symbol "c" in + let x = symbol "x" in + App (Abs (c, Case (Var c, [((some, [x]), Var x); ((none, []), Var c)])), + Constr (some, [peano_of_int 1])) + + (* (λc. case c of (Triple(x,y,z) → y)) Triple(1,2,3)) *) + let case_triple = + let c = symbol "c" in + let x = symbol "x" in + let y = symbol "y" in + let z = symbol "z" in + let triple = symbol "triple" in + App (Abs (c, Case (Var c, [((triple, [x;y;z]), Var y)])), + Constr (triple, List.map peano_of_int [1;2;3])) + + (* fix(λf.λc. case c of (s(x) → s(s(f x))) (z → z)) s(s(s(z))) *) + let fix_dup = + let f = symbol "f" in + let c = symbol "c" in + let x = symbol "x" in + App (Fix (f, Abs (c, Case (Var c, + [((s, [x]), peano_add 2 (App (Var f, Var x))); + ((z, []), peano_of_int 0)]))), + peano_of_int 3) + + (* fix(λf.λg.λc. case c of (s(x) → g (f g x)) (z → z)) (λy.s(s(y))) s(s(s(z))) *) + let fix_scale = + let f = symbol "f" in + let g = symbol "g" in + let c = symbol "c" in + let x = symbol "x" in + let y = symbol "y" in + App (App (Fix (f, Abs (g, Abs (c, Case (Var c, + [((s, [x]), App (Var g, (App (App (Var f, Var g), Var x)))); + ((z, []), peano_of_int 0)])))), + Abs (y, peano_add 2 (Var y))), + peano_of_int 3) +end + + +(**************************************************) +(* Untyped lambda calculus with De Bruijn indices *) +(**************************************************) +module DBILambda = struct + type dbi_symbol = int * symbol + type t = Var of dbi_symbol | App of t * t | Abs of symbol * t + | If of t * t * t | True | False + | Constr of t constr | Case of t * (symbol constr * t) list + | Fix of symbol * t + and 'a constr = symbol * 'a list + + let dbi dbis x = (find_idx_exn x dbis, x) + + let show_dbi_symbol (n, x) = show_symbol x + let rec show m = + match m with + | Var x -> show_dbi_symbol x + | App (m1, m2) -> "(" ^ show m1 ^ " " ^ show m2 ^ ")" + | Abs (x, m) -> "(λ" ^ show_symbol x ^ "." ^ show m ^ ")" + | If (m1, m2, m3) -> "if " ^ show m1 + ^ " then " ^ show m2 + ^ " else " ^ show m3 + | True -> "True" | False -> "False" + | Constr (x, ms) -> show_symbol x ^ "(" ^ concat_with ", " show ms ^ ")" + | Case (m, bs) -> "(case " ^ show m ^ " of " + ^ concat_with " " show_branch bs ^ ")" + | Fix (x, m) -> "fix(λ" ^ show_symbol x ^ "." ^ show m ^ ")" + and show_branch ((x, args), m) = + "(" ^ show_symbol x ^ "(" ^ concat_with "," show_symbol args ^ ") → " + ^ show m ^ ")" + let print = print_with show + + let of_lambda = + let rec of_lambda dbis = function + | Lambda.Var x -> let (n, x) = dbi dbis x in Var (n, x) + | Lambda.App (m1, m2) -> App (of_lambda dbis m1, of_lambda dbis m2) + | Lambda.Abs (x, m) -> Abs (x, of_lambda (x :: dbis) m) + | Lambda.If (m1, m2, m3) -> If (of_lambda dbis m1, + of_lambda dbis m2, of_lambda dbis m3) + | Lambda.True -> True | Lambda.False -> False + | Lambda.Constr (x, ms) -> Constr (x, List.map (of_lambda dbis) ms) + | Lambda.Case (m, bs) -> Case (of_lambda dbis m, + List.map (trans_br dbis) bs) + | Lambda.Fix (x, m) -> Fix (x, of_lambda (x :: dbis) m) + and trans_br dbis ((x, args), m) = + let dbis = List.rev args @ dbis in + ((x, args), of_lambda dbis m) in + of_lambda [] +end + + +(*******************) +(* Krivine Machine *) +(*******************) +module KM = struct + open DBILambda + + type st_elm = Clos of DBILambda.t * stack + | IfCont of DBILambda.t * DBILambda.t + | CaseCont of (symbol constr * t) list * stack + | FixClos of symbol * DBILambda.t * stack + and stack = st_elm list + + type state = DBILambda.t * stack * stack + + let reduce m = + let rec reduce (st : state) : DBILambda.t = + match st with + (* Pure lambda calculus *) + | (Var (0, _), s, Clos (m, e') :: e) -> reduce (m, s, e') + | (Var (0, _), s, FixClos (f, m, e') :: e) -> + reduce (m, s, FixClos (f, m, e') :: e') + | (Var (n, x), s, _ :: e) -> reduce (Var (n-1, x), s, e) + | (App (m1, m2), s, e) -> reduce (m1, Clos (m2, e) :: s, e) + | (Abs (_, m), c :: s, e) -> reduce (m, s, c :: e) + (* Conditionals *) + | (If (m1, m2, m3), s, e) -> reduce (m1, IfCont (m2, m3) :: s, e) + | (True, IfCont (m2, m3) :: s, e) -> reduce (m2, s, e) + | (False, IfCont (m2, m3) :: s, e) -> reduce (m3, s, e) + (* Case expressions (+ constructors) *) + | (Case (m, bs), s, e) -> reduce (m, CaseCont (bs, e) :: s, e) + | (Constr (x, ms), CaseCont (((x', args), m) :: bs, e') :: s, e) + when x == x' && List.length ms == List.length args -> + reduce (List.fold_left (fun m x -> Abs (x, m)) m args, + map_rev (fun m -> Clos (m, e)) ms @ s, e') + | (Constr (x, ms), CaseCont (_ :: bs, e') :: s, e) -> + reduce (Constr (x, ms), CaseCont (bs, e') :: s, e) + | (Constr (x, ms), s, e) -> + Constr (x, List.map (fun m -> reduce (m, s, e)) ms) + (* Fixpoints *) + | (Fix (x, m), s, e) -> reduce (m, s, FixClos (x, m, e) :: e) + (* Termination *) + | (m, [], []) -> m + | (_, _, _) -> m in + reduce (m, [], []) +end + + +let do_compile_and_red m = + let dbi_m = DBILambda.of_lambda m in + print_endline ("# Lambda term:\n " ^ DBILambda.show dbi_m); + let red_m = KM.reduce dbi_m in + print_endline ("# Reduced term:\n " ^ DBILambda.show red_m); + print_endline "--------------------------------------------------------------\n" + +let () = + let open Lambda in + List.iter do_compile_and_red [m1; plus; nested_if; constr_test; + case_some; case_triple; fix_dup; fix_scale] diff --git a/code/zam.ml b/code/zam.ml new file mode 100644 index 0000000..07fb85e --- /dev/null +++ b/code/zam.ml @@ -0,0 +1,546 @@ +let print_with f x = print_endline (f x) +let concat_with sep f xs = String.concat sep (List.map f xs) +let split n xs = + let rec split_acc n xs ys = match (n, ys) with + | (0, _) | (_, []) -> (List.rev xs, ys) + | (n, y :: ys) -> split_acc (n-1) (y::xs) ys in + split_acc n [] xs +let find_idx a = + let rec find_acc n = function + | [] -> raise Not_found + | (x :: xs) -> if a == x then n else find_acc (n+1) xs in + find_acc 0 +let rec repeat n x = if n == 0 then [] else x :: repeat (n-1) x +let fold_left1 f = function + | [] -> raise (Invalid_argument "empty string") + | (x::xs) -> List.fold_left f x xs + +let dbg_lev = 5 +let debug lev spaces s = + if dbg_lev >= lev + then print_endline (" -- " ^ String.concat "" (repeat spaces " ") ^ s) + +(* Compile, decompile and reduce errors *) +exception CpErr of string +exception DcErr of string +exception RdErr of string + +module CCLambda = struct + type symbol = string * int + let symbol : string -> symbol = + let id = ref 0 in + let gensym c : symbol = + let newid = !id in + id := !id + 1; + (c, newid) + in + gensym + + type t = Var of symbol | App of t * t | Abs of symbol * t + | Constr of t constr | Case of t * (symbol constr * t) list + | Fix of symbol * symbol list * symbol * t + | Acc of t + and 'a constr = symbol * 'a list + + let show_symbol (s, n) = + if dbg_lev > 2 then s ^ "/" ^ string_of_int n else s + let rec show m = + let show_branch ((x, vs), m) = + "(" ^ show_symbol x ^ "(" ^ concat_with "," show_symbol vs ^ ") → " + ^ show m ^ ")" in + match m with + | Var x -> show_symbol x + | App (m1, m2) -> "(" ^ show m1 ^ " " ^ show m2 ^ ")" + | Abs (x, m) -> "(λ" ^ show_symbol x ^ "." ^ show m ^ ")" + | Constr (x, ms) -> show_symbol x ^ "(" ^ concat_with ", " show ms ^ ")" + | Case (m, bs) -> "(case " ^ show m ^ " of " + ^ concat_with " " show_branch bs ^ ")" + | Fix (f, xs, c, m) -> + "fix_" ^ string_of_int (List.length xs) + ^ "(λ" ^ concat_with ".λ" show_symbol (f::xs@[c]) + ^ ". " ^ show m ^ ")" + | Acc m -> "[" ^ show m ^ "]" + let print = print_with show + + (* Auxiliar term-generating functions *) + let identity s = + let x = symbol s in + Abs (x, Var x) + + let rec appN n f m = if n = 0 then m else appN (n-1) f (App (f, m)) + let apps = fold_left1 (fun m n -> App (m, n)) + + let church_of_int n = + let f = symbol "f" in + let x = symbol "x" in + Abs (f, Abs (x, appN n (Var f) (Var x))) + + let none = symbol "None" + let some = symbol "Some" + let cons = symbol "Cons" + let nil = symbol "Nil" + + (* Peano arithmetic *) + let z = symbol "z" + let s = symbol "s" + + let rec peano_add n x = + if n == 0 then x else peano_add (n-1) (Constr (s, [x])) + + let peano_of_int n = peano_add n (Constr (z, [])) + + (* Examples *) + + (* (λx.λy. (x y)) (λxx.xx) *) + let partial = + let x = symbol "x" in + let y = symbol "y" in + App (Abs (x, Abs (y, App (Var x, Var y))), + identity "xx") + + (* (λm.λn.λf.λx. (m f)((n f) x) *) + let plus = + let m = symbol "m" in + let n = symbol "n" in + let f = symbol "f" in + let x = symbol "x" in + Abs (m, Abs (n, Abs (f, Abs (x, App (App (Var m, Var f), + App (App (Var n, Var f), Var x)))))) + + let _3plus1 = + App (App (plus, church_of_int 3), church_of_int 1) + + (* (λf.λx. f (f x)) (λy.y) (λz.z) *) + let twiceId = + let f = symbol "f" in + let x = symbol "x" in + App (App (Abs (f, Abs (x, App (Var f, App (Var f, Var x)))), + identity "y"), + identity "z") + + (* (λc. case c of (Some(x) → x) (None → c)) Some(s(z))) *) + let case_some = + let c = symbol "c" in + let x = symbol "x" in + App (Abs (c, Case (Var c, [((some, [x]), Var x); ((none, []), Var c)])), + Constr (some, [peano_of_int 1])) + + (* (λc. case c of (Cons(x, xs) → x) (Nil → Nil)) Cons(λx.x, Nil) *) + let case_head = + let c = symbol "c" in + let x = symbol "x" in + let xs = symbol "xs" in + App (Abs (c, Case (Var c, [((cons, [x;xs]), Var x); + ((nil, []), Constr (nil, []))])), + Constr (cons, [identity "m"; Constr (nil, [])])) + + (* fix_0(λf.λc. case c of (s(x) → s(s(f x))) (z → z)) s(s(s(z))) *) + let fix_dup = + let f = symbol "f" in + let c = symbol "c" in + let x = symbol "x" in + App (Fix (f, [], c, Case (Var c, + [((s, [x]), peano_add 2 (App (Var f, Var x))); + ((z, []), peano_of_int 0)])), + peano_of_int 3) + + (* fix_1(λf.λg.λc. case c of (s(x) → g(f x)) (z → z)) (λy.s(s(y))) s(s(s(z))) *) + let fix_scale = + let f = symbol "f" in + let g = symbol "g" in + let c = symbol "c" in + let x = symbol "x" in + let y = symbol "y" in + App (App (Fix (f, [g], c, Case (Var c, + [((s, [x]), App (Var g, (App (Var f, Var x)))); + ((z, []), peano_of_int 0)])), + Abs (y, peano_add 2 (Var y))), + peano_of_int 1) + + (* (λx.x) (λy. ((λz.z) y) (λt.t) *) + let acc_app = + let y = symbol "y" in + App (identity "x", + Abs (y, App (App (identity "z", + Var y), + identity "t"))) + + (* (λc. case c of (Cons(x, xs) → x) (Nil → Nil)) *) + let acc_case = + let c = symbol "c" in + let x = symbol "x" in + let xs = symbol "xs" in + Abs (c, Case (Var c, [((cons, [x;xs]), Var c); + ((nil, []), Constr (nil, []))])) + + (* fix_0(λf.λn. case c of (s(x) → s(s(f x))) (z → z)) *) + let acc_fix = + let f = symbol "f" in + let c = symbol "c" in + let x = symbol "x" in + Fix (f, [], c, Case (Var c, + [((s, [x]), peano_add 2 (App (Var f, Var x))); + ((z, []), peano_of_int 0)])) + +end + +module WeakRed : sig + type instrs + type mval + + val show_instrs : instrs -> string + val show_mval : mval -> string + + val compile : CCLambda.t -> instrs + val decompile : instrs -> CCLambda.t + + val am_reduce : instrs -> mval + val extract : mval -> CCLambda.t + + val reduce : CCLambda.t -> CCLambda.t +end = struct + open CCLambda + + type dbi = symbol * int + type instr = + | ACCESS of dbi + | CLOSURE of instrs + | ACCLOSURE of symbol + | PUSHRETADDR of instrs + | APPLY of int + | GRAB of symbol + | RETURN + | MAKEBLOCK of symbol * int + | SWITCH of (symbol constr * instrs) list + | CLOSUREREC of (symbol * symbol list * symbol) * instrs + | GRABREC of symbol + and instrs = instr list + and accum = + | NoVar of symbol + | NoApp of accum * mval list + | NoCase of accum * instrs * env + | NoFix of accum * instrs * env + and mval = + | Accu of accum + | Cons of mval constr + | Clos of instrs * env + | Ret of instrs * env * int + and env = mval list + and stack = mval list + and state = { + st_c : instrs; + st_e : env; + st_s : stack; + st_n : int; + } + + let show_dbi = function + | (x, i) -> + string_of_int i ^ + if dbg_lev > 2 then " (" ^ show_symbol x ^ ")" else "" + let rec show_instr = function + | ACCESS dbi -> "ACCESS(" ^ show_dbi dbi ^ ")" + | CLOSURE is -> "CLOSURE(" ^ show_instrs is ^ ")" + | ACCLOSURE x -> "ACCLOSURE([" ^ show_symbol x ^ "])" + | PUSHRETADDR is -> "PUSHRETADDR(" ^ show_instrs is ^ ")" + | APPLY i -> "APPLY(" ^ string_of_int i ^ ")" + | GRAB x -> "GRAB(" ^ show_symbol x ^ ")" + | RETURN -> "RETURN" + | MAKEBLOCK (x, n) -> "MAKEBLOCK(#" ^ show_symbol x ^ ", " ^ + string_of_int n ^ ")" + | SWITCH bs -> "SWITCH(" ^ concat_with ", " show_branch bs ^ ")" + | CLOSUREREC (_, is) -> "CLOSUREREC(" ^ show_instrs is ^ ")" + | GRABREC x -> "GRABREC(" ^ show_symbol x ^ ")" + and show_branch (((c, _), _), is) = c ^ " → " ^ show_instrs is + and show_accum = function + | NoVar x -> "{NoVar: " ^ show_symbol x ^ "}" + | NoApp (k, mvs) -> "{NoApp: " ^ show_accum k ^ ", " + ^ concat_with ", " show_mval mvs ^ "}" + | NoCase (k, is, e) -> "{NoCase: " ^ show_accum k ^ ", " + ^ show_instrs is ^ ", " ^ show_env e ^ "}" + | NoFix (k, is, e) -> "{NoFix: " ^ show_accum k ^ ", " + ^ show_instrs is ^ ", " ^ show_env e ^ "}" + and show_mval mval = match mval with + | Accu k -> show_accum k + | Cons ((s, _), mvs) -> + "{#" ^ s ^ if List.length mvs == 0 then "}" + else ": " ^ concat_with ", " show_mval mvs ^ "}" + | Clos (is, e) -> "{Tλ: (" ^ show_instrs is ^ "), " + ^ (if List.length e > 0 && List.hd e == mval + then "{Tλ }::" ^ show_env (List.tl e) + else show_env e) + ^ "}" + | Ret (is, e, n) -> "{: (" ^ show_instrs is ^ "), " ^ show_env e ^ ", " + ^ string_of_int n ^ "}" + and show_env e = "[" ^ concat_with ", " show_mval e ^ "]" + and show_instrs is = concat_with "; " show_instr is + + let show_stk stk = "| " ^ concat_with "\n | " show_mval stk + let show_st {st_c; st_e; st_s; st_n} = + "\n/---------------------------------------------------\n" + ^ " C: " ^ show_instrs st_c ^ "\n" + ^ " E: " ^ show_env st_e ^ "\n" + ^ " S: " ^ show_stk st_s ^ "\n" + ^ " N: " ^ string_of_int st_n ^ "\n" + ^ "\\---------------------------------------------------" + + let ret = [RETURN] + + let compile (m : CCLambda.t) : instrs = + let open CCLambda in + + let e = [] in + let rec compile' e (is : instrs) m = + debug 3 3 ("COMPILING: " ^ show m); + debug 3 3 (" IN ENV: " ^ concat_with ", " show_symbol e); + match m with + | Var x -> begin + try ACCESS(x, find_idx x e) :: is + with Not_found -> raise (CpErr ("Var " ^ fst x ^ " not found")) + end + | Abs (x, m) -> CLOSURE(GRAB x :: compile' (x :: e) ret m) :: is + | App (m1, m2) -> let cont = compile' e [APPLY(1)] m1 in + PUSHRETADDR(is) :: compile' e cont m2 + | Constr (x, args) -> let f arg cont = compile' e cont arg in + let cont = [MAKEBLOCK (x, List.length args)] in + List.fold_right f (List.rev args) (cont @ is) + | Case (m, bs) -> + let compile_branch ((c, args), m) = + let dbi' = List.rev args @ e in + ((c, args), compile' dbi' ret m) in + let bs' = List.map compile_branch bs in + PUSHRETADDR(is) :: compile' e [SWITCH(bs')] m + | Fix (f, xs, c, m) -> + let cont = compile' (c :: List.rev xs @ f :: e) ret m in + CLOSUREREC((f, xs, c), + List.map (fun x -> GRAB x) xs @ GRABREC c :: cont) :: is + | Acc (Var x) -> ACCLOSURE x :: is + | Acc _ -> raise (CpErr "Trying to compile non-var accumulator") in + compile' e ret m + + let rec decompile' e s is = + debug 3 3 ("DECOMPILING: " ^ show_instrs is); + debug 3 3 (" IN ENV: " ^ concat_with ", " CCLambda.show e); + debug 3 3 (" IN STK: " ^ concat_with ", " CCLambda.show s); + match is with + | [] -> List.hd s + | [RETURN] -> List.hd s + | (ACCESS (_, i) :: is') -> decompile' e (List.nth e i :: s) is' + | (CLOSURE c_is :: is') -> decompile' e (decompile' e s c_is :: s) is' + | (PUSHRETADDR r_is :: is') -> decompile' e (decompile' e s is' :: s) r_is + | (APPLY i :: is) -> begin + match (i, s) with + | (1, a::b::_) -> App (a, b) + | (n, a::s') -> App (a, decompile' e s' [APPLY (n-1)]) + | _ -> raise (DcErr "Unable to decompile APPLY") + end + | (GRAB x :: is') -> Abs (x, decompile' (Var x :: e) s is') + | (MAKEBLOCK (x, n) :: is') -> let (args, st') = split n s in + decompile' e (Constr (x, args) :: s) is' + | (SWITCH brs :: is') -> begin + let decompile_br ((c, parms), is) = + let parms_m = List.map (fun x -> Var x) parms in + ((c, parms), decompile' (List.rev parms_m @ e) s is) in + match s with + | [] -> Case (Var (symbol "_"), List.map decompile_br brs) + | (a::s') -> Case (a, List.map decompile_br brs) + end + | (CLOSUREREC ((f, xs, c), is') :: is) -> + let m = decompile' (e) s is' in + decompile' e (Fix (f, xs, c, m) :: s) is + | (GRABREC x :: is') -> Abs (x, decompile' (Var x :: e) s is') + | _ -> raise (DcErr "Unable to decompile (unknown instruction)") + let decompile = decompile' [] [] + + let rec extract mv = + debug 3 3 ("EXTRACTING: " ^ show_mval mv); + match mv with + | Clos (is, _) -> decompile is + | Cons (x, mvs) -> Constr (x, List.map extract mvs) + | Accu k -> + let rec extract_accu = function + | (NoVar x) -> Acc (Var x) + | (NoApp (k, mvs)) -> + Acc (apps (extract_accu k :: List.map extract mvs)) + | (NoCase (k, is, e)) -> begin + match decompile' (List.map extract e) [] is with + | Case (m, bs) -> + let accu = extract_accu k in + Acc (Case (accu, bs)) + | _ -> raise (DcErr "Invalid decompilation of CASE accum.") + end + | (NoFix (k, is, e)) -> begin + match decompile' (List.map extract e) [] is with + | Fix (f, xs, c, m) -> + Acc (Fix (f, xs, c, App (m, extract_accu k))) + | _ -> raise (DcErr "Invalid decompilation of fixpt accum.") + end in + extract_accu k + | _ -> raise (DcErr "Unable to extract") + + let am_reduce is = + debug 3 3 ("REDUCING: " ^ show_instrs is); + let rec eval st = + debug 4 4 (show_st st); + let {st_c=c; st_e=e; st_s=s; st_n=n} = st in + match c with + | [] -> raise (RdErr "Empty code section") + | (instr :: c) -> begin + match instr with + | ACCESS ((x, _), i) -> begin + try eval {st with st_c=c; st_s=(List.nth e i :: s)} + with Not_found -> raise (RdErr ("Var " ^ x ^ " not found")) + end + | CLOSURE c' -> eval {st with st_c=c; st_s=(Clos(c', e) :: s)} + | ACCLOSURE x -> eval {st with st_c=c; st_s=(Accu(NoVar x) :: s)} + | PUSHRETADDR c' -> eval {st with st_c=c; st_s=(Ret(c', e, n) :: s)} + | APPLY i -> begin + match s with + | (Clos (c', e') :: s) -> + eval {st_c=c'; st_e=e'; st_s=s; st_n=i} + | (Accu k :: s) -> begin + let (args, s') = split i s in + match s' with + | (Ret (c', e', n') :: s'') -> + eval {st_c=c'; st_e=e'; + st_s=(Accu(NoApp(k,args)))::s''; st_n=n'} + | _ -> raise (RdErr "APPLY over accu with invalid stack") + end + | _ -> raise (RdErr "APPLY over non-closure mval") + end + | GRAB _ -> begin + if n == 0 then + match s with + | (Ret (c', e', n') :: s) -> + let clos = Clos (instr :: c, e) in + eval {st_c=c'; st_e=e'; st_s=clos::s; st_n=n'} + | [] -> Clos (instr :: c, e) + | _ -> raise (RdErr "GRAB (n=0) over non-retval") + else + match s with + | (v :: s) -> eval {st_c=c; st_e=v::e; st_s=s; st_n=n-1} + | _ -> raise (RdErr "GRAB (n>0) over empty stack") + end + | RETURN -> begin + if n == 0 then + match s with + | (v :: Ret (c', e', n') :: s) -> + eval {st_c=c'; st_e=e'; st_s=v::s; st_n=n'} + | [v] -> v + | _ -> raise (RdErr "RETURN over empty stack or non-retval") + else + match s with + | (Clos (c', e') :: s) -> + eval {st_c=c'; st_e=e'; st_s=s; st_n=n} + | _ -> raise (RdErr "RETURN over empty stack or non-retval") + end + | MAKEBLOCK (x, m) -> let (vs, s') = split m s in + eval {st_c=c; st_e=e; + st_s=(Cons (x, vs)::s'); st_n=n} + | SWITCH bs -> begin + match s with + | (Cons (x, vs) :: s) -> + let (_, c') = try List.find (fun ((y, _), _) -> y == x) bs + with Not_found -> + raise (RdErr "SWITCH constr id not found") in + let e' = List.rev vs @ e in + eval {st_c=c'; st_e=e'; st_s=s; st_n=0} + | (Accu k :: s) -> + let accu = Accu (NoCase (k, instr :: c, e)) in + eval {st_c=ret; st_e=e; st_s=accu::s; st_n=0} + | _ -> raise (RdErr "SWITCH over empty stack or non-constr") + end + | CLOSUREREC (_, c') -> let rec v = Clos (c', v::e) in + eval {st with st_c=c; st_s=v::s} + | GRABREC _ -> begin + match (s, n) with + | ([Accu k], 1) -> Accu (NoFix (k, c, e)) + | (Accu k :: s, n) -> + let accu = Accu (NoFix (k, instr :: c, e)) in + eval {st_c=ret; st_e=e; st_s=accu::s; st_n=n-1} + | (Ret (c', e', n') :: s, n) -> + let clos = Clos (instr :: c, e) in + eval {st_c=c'; st_e=e'; st_s=clos::s; st_n=n'} + | (mval :: s, n) -> + eval {st_c=c; st_e=mval::e; st_s=s; st_n=n-1} + | ([], 0) -> Clos (instr :: c, e) + | _ -> raise (RdErr "GRABREC over empty stack or invalid mval") + end + end in + let st = {st_c = is; st_e = []; st_s = []; st_n = 0} in + eval st + + let reduce m = debug 2 1 ("V( " ^ show m ^ " )"); + match m with + | App (m1, m2) -> m |> compile |> am_reduce |> extract + | _ -> m +end + +module StrongRed = struct + open CCLambda + + let rec extract_unique = function + | Var x -> x + | Acc x -> extract_unique x + | _ -> raise (RdErr "Trying to extract invalid value") + + let unique x = symbol (fst x) + + let rec reduce m = + debug 2 0 ("N( " ^ show m ^ " )"); + match m with + | Fix (f, xs, c, m) -> + let xs' = List.map unique xs in + let f' = unique f in + let c' = unique c in + let accs = List.map (fun x -> Acc (Var x)) (f' :: xs' @ [c']) in + (* debug 2 10 (concat_with " # " show accs); *) + let m' = reduce (apps (m :: accs)) in + Fix (f', xs', c', m') + | _ -> readback (WeakRed.reduce m) + and readback m = + debug 2 1 ("R( " ^ show m ^ " )"); + match m with + | Abs (x, m) -> let u = unique x in + Abs (u, reduce (App (Abs (x, m), Acc (Var u)))) + | Constr (x, vs) -> Constr (x, List.map readback vs) + | Acc k -> readback_acc k + | App (Fix (f, xs, c, m), p) -> + App (reduce (Fix (f, xs, c, m)), readback p) + (* | Fix (f, xs, c, m) -> *) + | _ -> raise (RdErr "Readback of invalid value") + and readback_acc m = + debug 2 2 ("R'( " ^ show m ^ " )"); + match m with + | Var x -> Var x + | App (k, v) -> App (readback_acc k, readback v) + | Acc (Var x) -> Var x + | Case (k, bs) -> let x = extract_unique k in + let b = Abs (x, Case (Var x, bs)) in + let rb_branch ((c, xs), m) = + let us = List.map unique xs in + let acc_us = List.map (fun x -> Acc (Var x)) us in + ((c, us), reduce (App (b, Constr (c, acc_us)))) in + Case (readback_acc k, List.map rb_branch bs) + | _ -> raise (RdErr "Readback of invalid accumulator") +end + +let test_weakred m = + print_endline "WEAK REDUCTION TEST"; + print_endline ("Target expression: '" ^ CCLambda.show m ^ "'..."); + + print_string "Compiling... "; + let compiled = WeakRed.compile m in + + print_endline "Reducing..."; + let reduced = WeakRed.am_reduce compiled in + print_endline ("Final value: " ^ CCLambda.show (WeakRed.extract reduced)) + +let test_strongred m = + print_endline "STRONG REDUCTION TEST"; + print_endline ("Target expression: '" ^ CCLambda.show m ^ "'..."); + print_endline ("Final value: " ^ CCLambda.show (StrongRed.reduce m)) + +let () = + let m = CCLambda.fix_scale in + test_strongred m -- cgit v1.2.3