fixed merge
authorJim Pryor <profjim@jimpryor.net>
Mon, 20 Sep 2010 15:44:10 +0000 (11:44 -0400)
committerJim Pryor <profjim@jimpryor.net>
Mon, 20 Sep 2010 15:44:10 +0000 (11:44 -0400)
Signed-off-by: Jim Pryor <profjim@jimpryor.net>
code/lambda.cmi [new file with mode: 0644]
code/lambda.cmo [new file with mode: 0644]
code/lambda.js [moved from lambda.js with 100% similarity]
code/lambda.ml [new file with mode: 0644]
code/q_lambda.cmi [new file with mode: 0644]
code/q_lambda.cmo [new file with mode: 0644]
code/q_lambda.ml [new file with mode: 0644]
lambda-let.html

diff --git a/code/lambda.cmi b/code/lambda.cmi
new file mode 100644 (file)
index 0000000..532e6bb
Binary files /dev/null and b/code/lambda.cmi differ
diff --git a/code/lambda.cmo b/code/lambda.cmo
new file mode 100644 (file)
index 0000000..267ae7a
Binary files /dev/null and b/code/lambda.cmo differ
similarity index 100%
rename from lambda.js
rename to code/lambda.js
diff --git a/code/lambda.ml b/code/lambda.ml
new file mode 100644 (file)
index 0000000..3f1435d
--- /dev/null
@@ -0,0 +1,374 @@
+(* *)
+
+module Private =  struct
+    type var_t = int*string
+    let var v = (0,v)
+    let string_of_var (i,v) = v ^ String.make i '\''
+    let equal_var (i1,v1) (i2,v2) = i1 == i2 && (String.compare v1 v2 == 0)
+
+    type lambda_t = [ `Var of var_t | `Lam of var_t * lambda_t | `App of lambda_t * lambda_t ]
+
+    type debruijn_t = [ `Var of var_t | `DVar of int | `DLam of debruijn_t | `DApp of debruijn_t*debruijn_t ]
+
+    let db_subst (expr : debruijn_t) (m : int) (repl : debruijn_t) =
+        let rec rename m i = function
+        | `Var _ as term -> term
+        | `DVar j as term when j < i -> term
+        | `DVar j -> `DVar (j + m - 1)
+        | `DApp(n1,n2) -> `DApp(rename m i n1, rename m i n2)
+        | `DLam n -> `DLam(rename m (i+1) n)
+        in let rec loop m = function
+        | `Var _ as term -> term
+        | `DVar n as term when n < m -> term
+        | `DVar n when n > m -> `DVar (n-1)
+        | `DVar n -> rename n 1 repl
+        | `DApp(m1,m2) -> `DApp(loop m m1, loop m m2)
+        | `DLam mterm -> `DLam(loop (m+1) mterm)
+        in loop m expr
+
+    let db (expr : lambda_t) : debruijn_t =
+        let pos seq (target : var_t) handler default =
+            let rec loop (i : int) = function
+            | [] -> default
+            | x::xs when equal_var x target -> handler i
+            | _::xs -> loop (i+1) xs
+            in loop 1 seq
+        in let rec loop seq = function
+        | `Var v as term -> pos seq v (fun i -> `DVar i) term
+        | `Lam (v,t) -> `DLam(loop (v::seq) t)
+        | `App (t1,t2) -> `DApp(loop seq t1, loop seq t2)
+        in loop [] expr
+
+    let rec db_equal (t1 : debruijn_t) (t2 : debruijn_t) = match (t1,t2) with
+    | (`Var v1,`Var v2) -> equal_var v1 v2
+    | (`DVar i1, `DVar i2) -> i1 == i2
+    | (`DApp(m1,m2),`DApp(n1,n2)) -> db_equal m1 n1 && db_equal m2 n2
+    | (`DLam(t1),`DLam(t2)) -> db_equal t1 t2
+    | _ -> false
+
+    let rec db_contains (t1 : debruijn_t) (t2 : debruijn_t) = match (t1,t2) with
+    | (`Var v1,`Var v2) -> equal_var v1 v2
+    | (`DVar i1, `DVar i2) -> i1 == i2
+    | (`DApp(m1,m2),`DApp(n1,n2)) when db_equal m1 n1 && db_equal m2 n2 -> true
+    | (`DApp(m1,m2), term) -> db_contains m1 term || db_contains m2 term
+    | (`DLam(t1),`DLam(t2)) when db_equal t1 t2 -> true
+    | (`DLam(t1), term) -> db_contains t1 term
+    | _ -> false
+
+    (* non-normalizing string_of_lambda *)
+    let string_of_lambda (expr : lambda_t) =
+        let rec top = function
+            | `Var v -> string_of_var v
+            | `Lam _ as t -> "fun " ^ funct t
+            | `App ((`App _ as t1),t2) -> top t1 ^ " " ^ atom t2
+            | `App (t1,t2) -> atom t1 ^ " " ^ atom t2
+        and atom = function
+            | `Var v -> string_of_var v
+            | `Lam _ as t -> "(fun " ^ funct t ^ ")"
+            | `App _ as t -> "(" ^ top t ^ ")"
+        and funct = function
+            | `Lam (v,(`Lam _ as t)) -> (string_of_var v) ^ " " ^ funct t
+            | `Lam (v,t) -> (string_of_var v) ^ " -> " ^ top t
+        in top expr
+
+
+    (* evaluator based on http://okmij.org/ftp/Haskell/Lambda_calc.lhs *)
+
+    (* if v occurs free_in term, returns Some v' where v' is the highest-tagged
+     * variable with the same name as v occurring (free or bound) in term *)
+
+    let free_in ((tag, name) as v) term =
+        let rec loop = function
+        | `Var((tag', name') as v') ->
+                if name <> name' then false, v
+                else if tag = tag' then true, v
+                else false, v'
+        | `App(t1, t2) ->
+                let b1, ((tag1, _) as v1) = loop t1 in
+                let b2, ((tag2, _) as v2) = loop t2 in
+                b1 || b2, if tag1 > tag2 then v1 else v2
+        | `Lam(x, _) when x = v -> (false, v)
+        | `Lam(_, body) -> loop body
+        in match loop term with
+        | false, _ -> None
+        | true, v -> Some v
+
+    let rec subst v st = function
+        | term when st = `Var v -> term
+        | `Var x when x = v -> st
+        | `Var _ as term -> term
+        | `App(t1,t2) -> `App(subst v st t1, subst v st t2)
+        | `Lam(x, _) as term when x = v -> term
+        (* if x is free in the inserted term st, a capture is possible
+         * we handle by ...
+         *)
+        | `Lam(x, body) ->
+                (match free_in x st with
+                (* x not free in st, can substitute st for v without any captures *)
+                | None -> `Lam(x, subst v st body)
+                (* x free in st, need to alpha-convert `Lam(x, body) *)
+                | Some max_x ->  
+                    let bump_tag (tag, name) (tag', _) =
+                        (max tag tag') + 1, name in
+                    let bump_tag' ((_, name) as v1) ((_, name') as v2) =
+                        if name = name' then bump_tag v1 v2 else v1 in
+                    (* bump x > max_x from st, then check whether
+                     * it also needs to be bumped > v
+                     *)
+                    let uniq_x = bump_tag' (bump_tag x max_x) v in
+                    let uniq_x' = (match free_in uniq_x body with
+                        | None -> uniq_x
+                        (* bump uniq_x > max_x' from body *)
+                        | Some max_x' -> bump_tag uniq_x max_x'
+                    ) in
+                    (* alpha-convert body *)
+                    let body' = subst x (`Var uniq_x') body in
+                    (* now substitute st for v *)
+                    `Lam(uniq_x', subst v st body')
+                )
+
+    let check_eta = function
+        | `Lam(v, `App(t, `Var u)) when v = u && free_in v t = None -> t
+        | (_ : lambda_t) as term -> term
+
+    exception Lambda_looping;;
+
+    let eval ?(eta=false) (expr : lambda_t) : lambda_t =
+        let rec looping (body : debruijn_t) = function
+        | [] -> false
+        | x::xs when db_equal body x -> true
+        | _::xs -> looping body xs
+        in let rec loop (stack : lambda_t list) (body : lambda_t) = 
+            match body with
+            | `Var v as term -> unwind term stack
+            | `App(t1, t2) as term -> loop (t2::stack) t1
+            | `Lam(v, body) -> (match stack with
+                | [] ->
+                    let term = (`Lam(v, loop [] body)) in
+                        if eta then check_eta term else term
+                | t::rest -> loop rest (subst v t body)
+            )
+        and unwind t1 = function
+        | [] -> t1
+        | t2::ts -> unwind (`App(t1, loop [] t2)) ts
+        in loop [] expr
+
+
+    (* (Oleg's version of) Ken's evaluator; doesn't seem to work -- requires laziness? *)
+
+    let eval' ?(eta=false) (expr : lambda_t) : lambda_t =
+        let rec loop = function
+        | `Var v as term -> term
+        | `Lam(v, body) ->
+                let term = (`Lam(v, loop body)) in
+                    if eta then check_eta term else term
+        | `App(`App _ as t1, t2) ->
+            (match loop t1 with
+                | `Lam _ as redux -> loop (`App(redux, t2))
+                | nonred_head -> `App(nonred_head, loop t2)
+            )
+        | `App(t1, t2) -> `App(t1, loop t2)
+        in loop expr
+
+    let cbv ?(aggressive=true) (expr : lambda_t) : lambda_t =
+        let rec loop = function
+        | `Var x as term -> term
+        | `App(t1,t2) ->
+                let t2' = loop t2 in
+                (match loop t1 with
+                | `Lam(x, t) -> loop (subst x t2' t)
+                | _ as term -> `App(term, t2')
+                )
+        | `Lam(x, t) as term ->
+                if aggressive then `Lam(x, loop t)
+                else term
+        in loop expr
+
+
+
+    (*
+        module Sorted = struct
+            let rec cons y = function
+                | x :: _ as xs when x = y -> xs
+                | x :: xs when x < y -> x :: cons y xs
+                | xs [* [] or x > y *] -> y :: xs
+
+            let rec mem y = function
+                | x :: _ when x = y -> true
+                | x :: xs when x < y -> mem y xs
+                | _ [* [] or x > y *] -> false
+
+            let rec remove y = function
+                | x :: xs when x = y -> xs
+                | x :: xs when x < y -> x :: remove y xs
+                | xs [* [] or x > y *] -> xs
+
+            let rec merge x' y' = match x', y' with
+                | [], ys -> ys
+                | xs, [] -> xs
+                | x::xs, y::ys ->
+                    if x < y then x :: merge xs y'
+                    else if x = y then x :: merge xs ys
+                    else [* x > y *] y :: merge x' ys
+        end
+
+        let free_vars (expr : lambda_t) : string list =
+            let rec loop = function
+                | `Var x -> [x]
+                | `Lam(x,t) -> Sorted.remove x (loop t)
+                | `App(t1,t2) -> Sorted.merge (loop t1) (loop t2)
+            in loop expr
+
+        let free_in v (expr : lambda_t) =
+            Sorted.mem v (free_vars t)
+
+        let new_var =
+            let counter = ref 0 in
+            fun () -> (let z = !counter in incr counter; "_v"^(string_of_int z))
+
+        ...
+        | `Lam(x, body) as term when not (free_in v body) -> term
+        | `Lam(y, body) when not (free_in y st) -> `Lam(y, subst v st body)
+        | `Lam(y, body) ->
+            let z = new_var () in
+            subst v st (`Lam(z, subst y (`Var z) body))
+    *)
+
+
+
+    (*
+
+    let bound_vars (expr : lambda_t) : string list =
+        let rec loop = function
+            | `Var x -> []
+            | `Lam(x,t) -> Sorted.cons x (loop t)
+            | `App(t1,t2) -> Sorted.merge (loop t1) (loop t2)
+        in loop expr
+
+    let reduce_cbv ?(aggressive=true) (expr : lambda_t) : lambda_t =
+        let rec loop = function
+        | `Var x as term -> term
+        | `App(t1,t2) ->
+                let t2' = loop t2 in
+                (match loop t1 with
+                | `Lam(x, t) -> loop (subst x t2' t)
+                | _ as term -> `App(term, t2')
+                )
+        | `Lam(x, t) as term ->
+                if aggressive then `Lam(x, loop t)
+                else term
+        in loop expr
+
+    let reduce_cbn (expr : lambda_t) : lambda_t =
+        let rec loop = function
+        | `Var x as term -> term
+        | `Lam(v, body) ->
+                check_eta (`Lam(v, loop body))
+        | `App(t1,t2) ->
+                (match loop t1 with
+                | `Lam(x, t) -> loop (subst x t2 t)
+                | _ as term -> `App(term, loop t2)
+                )
+        in loop expr
+
+    *)
+
+
+    (*
+
+    type env_t = (string * lambda_t) list
+
+    let subst body x value =
+        ((fun env ->
+            let new_env = (x, value) :: env in
+            body new_env) : env_t -> lambda_t)
+
+    type strategy_t = By_value | By_name
+
+    let eval (strategy : strategy_t) (expr : lambda_t) : lambda_t =
+        in let rec inner = function
+            | `Var x as t ->
+                (fun env ->
+                    try List.assoc x env with
+                    | Not_found -> t)
+            | `App(t1, value) -> 
+                (fun env ->
+                    let value' =
+                        if strategy = By_value then inner value env else value in
+                    (match inner t1 env with
+                    | `Lam(x, body) ->
+                        let body' = (subst (inner body) x value' env) in
+                        if strategy = By_value then body' else inner body' env
+                    | (t1' : lambda_t) -> `App(t1', inner value env)
+                    )
+                )
+            | `Lam(x, body) ->
+                (fun env ->
+                    let v = new_var () in
+                    `Lam(v, inner body ((x,`Var v) :: env)))
+        in inner expr ([] : env_t)
+
+    let pp_env env =
+        let rec loop acc = function
+            | [] -> acc
+            | (x,term)::es -> loop ((x ^ "=" ^ string_of_lambda term) :: acc) es
+        in "[" ^ (String.concat ", " (loop [] (List.rev env))) ^ "]"
+
+    let eval (strategy : strategy_t) (expr : lambda_t) : lambda_t =
+        let new_var =
+            let counter = ref 0 in
+            fun () -> (let z = !counter in incr counter; "_v"^(string_of_int z))
+        in let rec inner term =
+            begin
+            Printf.printf "starting [ %s ]\n" (string_of_lambda term);
+            let res = match term with
+            | `Var x as t ->
+                (fun env ->
+                    try List.assoc x env with
+                    | Not_found -> t)
+            | `App(t1, value) -> 
+                (fun env ->
+                    let value' =
+                        if strategy = By_value then inner value env else value in
+                    (match inner t1 env with
+                    | `Lam(x, body) ->
+                        let body' = (subst (inner body) x value' env) in
+                        if strategy = By_value then body' else inner body' env
+                    | (t1' : lambda_t) -> `App(t1', inner value env)
+                    )
+                )
+            | `Lam(x, body) ->
+                (fun env ->
+                    let v = new_var () in
+                    `Lam(v, inner body ((x,`Var v) :: env)))
+            in
+            (fun env -> 
+                (Printf.printf "%s with %s => %s\n" (string_of_lambda term) (pp_env env) (string_of_lambda (res env)); res env))
+            end
+        in inner expr ([] : env_t)
+
+    *)
+
+    let normal ?(eta=false) expr = eval ~eta expr
+
+    let normal_string_of_lambda ?(eta=false) (expr : lambda_t) =
+        string_of_lambda (normal ~eta expr)
+
+    let rec to_int expr = match expr with
+        | `Lam(s, `Lam(z, `Var z')) when z' = z -> 0
+        | `Lam(s, `Var s') when s = s' -> 1
+        | `Lam(s, `Lam(z, `App (`Var s', t))) when s' = s -> 1 + to_int (`Lam(s, `Lam(z, t)))
+        | _ -> failwith (normal_string_of_lambda expr ^ " is not a church numeral")
+
+    let int_of_lambda ?(eta=false) (expr : lambda_t) =
+        to_int (normal ~eta expr)
+
+end
+
+type lambda_t = Private.lambda_t
+open Private
+let var = var
+let pp, pn, pi = string_of_lambda, normal_string_of_lambda, int_of_lambda
+let pnv,piv= (fun expr -> string_of_lambda (cbv expr)), (fun expr -> to_int (cbv expr))
+let db, db_equal, db_contains = db, db_equal, db_contains
+
diff --git a/code/q_lambda.cmi b/code/q_lambda.cmi
new file mode 100644 (file)
index 0000000..f14aaed
Binary files /dev/null and b/code/q_lambda.cmi differ
diff --git a/code/q_lambda.cmo b/code/q_lambda.cmo
new file mode 100644 (file)
index 0000000..8fbc229
Binary files /dev/null and b/code/q_lambda.cmo differ
diff --git a/code/q_lambda.ml b/code/q_lambda.ml
new file mode 100644 (file)
index 0000000..66762e5
--- /dev/null
@@ -0,0 +1,51 @@
+(* Please keep me in sync with brion.inria.fr/gallium/index.php/Lambda_calculus_quotations *)
+
+open Camlp4.PreCast;;
+module CamlSyntax = Camlp4OCamlParser.Make(Camlp4OCamlRevisedParser.Make(Syntax));;
+
+let expr_of_string = CamlSyntax.Gram.parse_string CamlSyntax.expr_eoi;;
+
+module LambdaGram = MakeGram(Lexer);;
+
+let term = LambdaGram.Entry.mk "term";;
+let term_eoi = LambdaGram.Entry.mk "lambda term quotation";;
+
+Camlp4_config.antiquotations := true;;
+
+EXTEND LambdaGram
+  GLOBAL: term term_eoi;
+  term:
+    [ "top"
+      [ "fun"; v = var; "->"; t = term -> <:expr< `Lam(var $v$, $t$) >>
+      | "fun"; v = var; v' = var; "->"; t = term -> <:expr< `Lam(var $v$, `Lam(var $v'$, $t$)) >>
+      | "fun"; v = var; v' = var; v'' = var; "->"; t = term -> <:expr< `Lam(var $v$, `Lam(var $v'$, `Lam(var $v''$, $t$))) >>
+      | "fun"; v = var; v' = var; v'' = var; v''' = var; "->"; t = term -> <:expr< `Lam(var $v$, `Lam(var $v'$, `Lam(var $v''$, `Lam(var $v'''$, $t$)))) >>
+      | "fun"; v = var; v' = var; v'' = var; v''' = var; v'''' = var; "->"; t = term -> <:expr< `Lam(var $v$, `Lam(var $v'$, `Lam(var $v''$, `Lam(var $v'''$, `Lam(var $v''''$, $t$))))) >>
+      ]
+
+    | "app"
+      [ t1 = SELF; t2 = SELF           -> <:expr< `App($t1$, $t2$) >> ]
+
+    | "simple"
+      [ `ANTIQUOT((""|"term"), a)      -> expr_of_string _loc a
+       | v = var                        -> <:expr< `Var(var $v$) >>
+       | "("; t = term; ")"             -> t 
+      ]
+
+    ];
+  var:
+    [[ v = LIDENT               -> <:expr< $str:v$ >>
+     | `ANTIQUOT((""|"var"), a) -> expr_of_string _loc a
+    ]];
+  term_eoi:
+    [[ t = term; `EOI -> t ]];
+END;;
+
+let expand_lambda_quot_expr loc _loc_name_opt quotation_contents =
+  LambdaGram.parse_string term_eoi loc quotation_contents;;
+
+(* to have this syntax <:lam< fun k -> k >> *)
+Syntax.Quotation.add "lam" Syntax.Quotation.DynAst.expr_tag expand_lambda_quot_expr;;
+
+Syntax.Quotation.default := "lam";;
+
index 8abd350..fd8dece 100644 (file)
@@ -1,7 +1,7 @@
 <html>
 <head>
 <title>Lambda evaluator with lets</title>
-<script language=JavaScript src="lambda.js"></script>
+<script language=JavaScript src="code/lambda.js"></script>
 </head>
 <body>