dtlc

dependently-typed lambda calculus toy
git clone git://git.rr3.xyz/dtlc
Log | Files | Refs | README | LICENSE

commit 680d5ffc27c92e9f504ced9ebd714f403d9174a6
parent cf53b44cb71672987ab0f078f94b0645eb646398
Author: Robert Russell <robertrussell.72001@gmail.com>
Date:   Tue, 19 Dec 2023 22:34:37 -0800

Return to working condition

Diffstat:
MMakefile | 20++++++++++++++++++--
Mcommon.ml | 5-----
Melab.ml | 69+++++++++++++++++++++++++++++++++++++--------------------------------
Meval.ml | 34+++++++++++++++++-----------------
Mmain.ml | 11++++-------
Mvalue.ml | 10+++++-----
6 files changed, 81 insertions(+), 68 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,4 +1,20 @@ -main: loc.ml node.ml common.ml field.ml concrete.ml parser.ml lexer.ml abstract.ml cnctoabs.ml main.ml #core.ml value.ml eval.ml elab.ml main.ml +SRC = \ + loc.ml \ + node.ml \ + common.ml \ + field.ml \ + concrete.ml \ + parser.ml \ + lexer.ml \ + abstract.ml \ + cnctoabs.ml \ + internal.ml \ + value.ml \ + eval.ml \ + elab.ml \ + main.ml + +main: $(SRC) ocamlfind ocamlopt -o $@ -g -linkpkg -package zarith $^ lexer.ml: lexer.mll @@ -6,7 +22,7 @@ lexer.ml: lexer.mll parser.ml: parser.mly ocamlyacc -v parser.mly - rm parser.mli # Hack + @rm parser.mli # Hack .PHONY: clean clean: diff --git a/common.ml b/common.ml @@ -2,11 +2,6 @@ type ident = string type index = int type level = int -(* -exception Error of loc * msg -let error loc msg = raise (TypeError) -*) - (* Short-circuiting AND fold_left. *) let rec all2 f xs ys = match xs, ys with | x :: xs, y :: ys -> f x y && all2 f xs ys diff --git a/elab.ml b/elab.ml @@ -4,6 +4,10 @@ module A = Abstract module I = Internal module V = Value +exception ElabError of Loc.t * string + +let error loc msg = raise (ElabError (loc, msg)) + (* TODO: use a hashtable or map for ident -> level lookups *) type context = { len: int; @@ -47,8 +51,8 @@ let bind_def ctx x v a = { (* Add `x : a` to ctx. *) let bind_arb ctx x a = bind_def ctx x (V.Arb ctx.len) a -let rec infer ctx = function -| A.Let (A.PAnnot (p, a), scrutinee, body) -> +let rec infer ctx (Node.Of (loc, t)) = match t with +| A.Let (Node.Of (_, A.PAnnot (p, a)), scrutinee, body) -> let a = check ctx a (V.Intrin I.Type) in let va = eval ctx.values a in let x = check_patt ctx p va in @@ -63,17 +67,17 @@ let rec infer ctx = function let (body, vb) = infer (bind_def ctx x vscrutinee va) body in (I.Let (scrutinee, body), vb) | A.Match _ -> failwith "no impl: match" -| A.Annot (tm, a) -> +| A.Annot (t, a) -> let a = check ctx a (V.Intrin I.Type) in let va = eval ctx.values a in - let tm = check ctx tm va in - (tm, va) + let t = check ctx t va in + (t, va) | A.App (f, args) -> let (f, fty) = infer ctx f in begin match fty with | V.FnType (env, arity, doms, cod) -> if List.length args <> arity then - failwith "type error: arity mismatch in application" + error loc "arity mismatch in application" else let rec go env args doms = match args, doms with | arg :: args, dom :: doms -> @@ -86,21 +90,18 @@ let rec infer ctx = function | _, _ -> failwith "impossible" in let (args, vcod) = go env args doms in (I.App (f, args), vcod) - | _ -> failwith "type error: expected function type in application" + | _ -> error loc "expected function in application" end -| A.Access _ -> failwith "no impl: access" -| A.Index _ -> failwith "no impl: index" -| A.Deref _ -> failwith "no impl: deref" | A.Fn (ps, body) -> let rec go ctx = function - | A.PAnnot (p, dom) :: ps -> + | Node.Of (_, A.PAnnot (p, dom)) :: ps -> let dom = check ctx dom (V.Intrin I.Type) in let vdom = eval ctx.values dom in let x = check_patt ctx p vdom in let (body, doms, vcod) = go (bind_arb ctx x vdom) ps in (body, dom :: doms, vcod) - | _ :: ps -> - failwith "type error: can not infer type for unannotated function parameter" + | Node.Of (loc, _) :: _ -> + error loc "can not infer type for unannotated function parameter" | [] -> let (body, vcod) = infer ctx body in (body, [], vcod) in @@ -111,15 +112,18 @@ let rec infer ctx = function | A.FnType (anns, cod) -> let arity = List.length anns in let rec go ctx = function - | (p, dom) :: anns -> - let cdom = check ctx dom (V.Intrin I.Type) in - let vdom = eval ctx.values cdom in + | Node.Of (_, ann) :: anns -> + let (p, dom) = match ann with + | A.AType dom -> (Loc.None @$ A.PWild, dom) + | A.APatt (p, dom) -> (p, dom) in + let dom = check ctx dom (V.Intrin I.Type) in + let vdom = eval ctx.values dom in let x = check_patt ctx p vdom in - let (cdoms, ccod) = go (bind_arb ctx x vdom) anns in - (cdom :: cdoms, ccod) + let (doms, cod) = go (bind_arb ctx x vdom) anns in + (dom :: doms, cod) | [] -> ([], check ctx cod (V.Intrin I.Type)) in - let (cdoms, ccod) = go ctx anns in - (I.FnType (arity, cdoms, ccod), V.Intrin I.Type) + let (doms, cod) = go ctx anns in + (I.FnType (arity, doms, cod), V.Intrin I.Type) | A.Data _ -> failwith "no impl: data" | A.DataType _ -> failwith "no impl: data type" | A.Nat n -> (I.Nat n, V.Intrin I.NatType) @@ -127,13 +131,13 @@ let rec infer ctx = function let rec go i ys ts = match ys, ts with | Some y :: ys, t :: ts -> if x = y then (I.Var i, t) else go (i + 1) ys ts | None :: ys, _ :: ts -> go (i + 1) ys ts - | [], [] -> failwith ("unbound identifier: " ^ x) + | [], [] -> error loc ("unbound identifier: " ^ x) | _, _ -> failwith "impossible" in go 0 ctx.names ctx.types -and check ctx tm vty = match tm, vty with +and check ctx (Node.Of (loc, t') as t) va = match t', va with (* TODO: Match, Data *) -| A.Let (A.PAnnot (p, a), scrutinee, body), vb -> +| A.Let (Node.Of (_, A.PAnnot (p, a)), scrutinee, body), vb -> let a = check ctx a (V.Intrin I.Type) in let va = eval ctx.values a in let x = check_patt ctx p va in @@ -149,7 +153,7 @@ and check ctx tm vty = match tm, vty with I.Let (scrutinee, body) | A.Fn (ps, body), V.FnType (env, arity, doms, cod) -> if List.length ps <> arity then - failwith "type error: arity mismatch" + error loc "arity mismatch" else let rec go ctx ps env doms = match ps, doms with | p :: ps, dom :: doms -> @@ -164,24 +168,25 @@ and check ctx tm vty = match tm, vty with | _, _ -> failwith "impossible" in let cbody = go ctx ps env doms in I.Fn (arity, cbody) -| tm, vexpected -> - let (tm, vinferred) = infer ctx tm in +| _, vexpected -> + let (t, vinferred) = infer ctx t in if conv ctx.len vexpected vinferred then - tm + t else - failwith "type error: expected/inferred mismatch" + (* TODO: pretty-print types *) + error loc "expected/inferred mismatch" -and check_patt ctx {loc; x = p} va = match p with +and check_patt ctx (Node.Of (loc, p)) va = match p with | A.PWild -> None | A.PBind x -> Some x -| A.PAssign _ -> failwith "no impl: assign pattern" | A.PAnnot (p, b) -> let b = check ctx b (V.Intrin I.Type) in - let vb = eval ctx.values cb in + let vb = eval ctx.values b in if conv ctx.len va vb then check_patt ctx p va else - failwith "pattern does not unify with inferred type" + (* TODO: pretty-print types *) + error loc "pattern does not unify with inferred type" | A.PData _ -> failwith "no impl: data pattern" | A.PNat _ -> failwith "no impl: nat pattern" | A.PAnd _ -> failwith "no impl: and pattern" diff --git a/eval.ml b/eval.ml @@ -1,5 +1,5 @@ open Common -module C = Core +module I = Internal module V = Value (* Extend env with values Arb l, Arb (l+1), ..., Arb (l+n-1). *) @@ -9,31 +9,31 @@ let weaken env l n = go env l let rec eval env = function -| C.Let (scrutinee, body) -> eval (eval env scrutinee :: env) body -| C.Case _ -> failwith "no impl: case" -| C.App (f, args) -> +| I.Let (scrutinee, body) -> eval (eval env scrutinee :: env) body +| I.Case _ -> failwith "no impl: case" +| I.App (f, args) -> begin match eval env f, List.map (eval env) args with (* β-reduction *) | V.Fn (cap, _, body), vargs -> eval (List.rev_append vargs cap) body - | V.Intrin C.NatOpAdd, [V.Nat m; V.Nat n] -> V.Nat (Z.add m n) - | V.Intrin C.NatOpMul, [V.Nat m; V.Nat n] -> V.Nat (Z.mul m n) + | V.Intrin I.NatOpAdd, [V.Nat m; V.Nat n] -> V.Nat (Z.add m n) + | V.Intrin I.NatOpMul, [V.Nat m; V.Nat n] -> V.Nat (Z.mul m n) (* neutral application *) | vf, vargs -> V.App (vf, vargs) end -| C.Fn (arity, body) -> V.Fn (env, arity, body) -| C.FnType (arity, doms, cod) -> V.FnType (env, arity, doms, cod) -| C.Nat n -> V.Nat n -| C.Var i -> List.nth env i -| C.Intrin a -> V.Intrin a +| I.Fn (arity, body) -> V.Fn (env, arity, body) +| I.FnType (arity, doms, cod) -> V.FnType (env, arity, doms, cod) +| I.Nat n -> V.Nat n +| I.Var i -> List.nth env i +| I.Intrin a -> V.Intrin a (* TODO: quote of eval normalizes terms; in some cases below, we probabaly * don't need to eval before quoting *) let rec quote l = function | V.Case _ -> failwith "no impl: case" -| V.App (f, args) -> C.App (quote l f, List.map (quote l) args) +| V.App (f, args) -> I.App (quote l f, List.map (quote l) args) | V.Fn (env, arity, body) -> let vbody = eval (weaken env l arity) body in - C.Fn (arity, quote (l + arity) vbody) + I.Fn (arity, quote (l + arity) vbody) | V.FnType (env, arity, doms, cod) -> let rec go l env = function | dom :: doms -> @@ -42,10 +42,10 @@ let rec quote l = function (cdom :: cdoms, ccod) | [] -> ([], quote l (eval env cod)) in let (cdoms, ccod) = go l env doms in - C.FnType (arity, cdoms, ccod) -| V.Nat n -> C.Nat n -| V.Arb i -> C.Var (l - i - 1) -| V.Intrin a -> C.Intrin a + I.FnType (arity, cdoms, ccod) +| V.Nat n -> I.Nat n +| V.Arb i -> I.Var (l - i - 1) +| V.Intrin a -> I.Intrin a let rec quote_telescope l = function | t :: ts -> quote l t :: quote_telescope (l + 1) ts diff --git a/main.ml b/main.ml @@ -7,14 +7,11 @@ let buf = Lexing.from_string "\ three: N := fn A, z, s => s (s (s z));\ five := add two three;\ five Nat 0 (fn n => n + 1)\ - ≈ " let concrete = Parser.start Lexer.token buf let abstract = Cnctoabs.term concrete -(* let ctx = Elab.default_ctx -let (core, core_type) = Elab.infer ctx abstract -let norm = Eval.quote ctx.len (Eval.eval ctx.values core) -let () = print_endline (Core.to_string 0 core) -let () = print_endline (Core.to_string 0 norm) -*) +let (internal, ty) = Elab.infer ctx abstract +let internal' = Eval.quote ctx.len (Eval.eval ctx.values internal) +let () = print_endline (Internal.to_string 0 internal) +let () = print_endline (Internal.to_string 0 internal') diff --git a/value.ml b/value.ml @@ -1,12 +1,12 @@ open Common -module C = Core +module I = Internal type value = -| Case of value * environ * C.case list +| Case of value * environ * I.case list | App of value * value list -| Fn of environ * int * C.term -| FnType of environ * int * C.term list * C.term +| Fn of environ * int * I.term +| FnType of environ * int * I.term list * I.term | Nat of Z.t | Arb of level -| Intrin of C.intrin +| Intrin of I.intrin and environ = value list