-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathpmp.ml
173 lines (147 loc) · 6.43 KB
/
pmp.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
open Util
open Core
open Syntax
open Value
open Norm
open Parser
open Asai.Range
let () = Arity.install ()
let unlocated (value : 'a) : 'a located = { value; loc = None }
(* Poor man's parser, reusing the OCaml parser to make a vaguely usable syntax *)
(* Abstract syntax terms with variable names *)
type pmt =
| Var : string -> pmt
| Const : string -> pmt
| Field : pmt * string -> pmt
| UU : pmt
| Pi : string * pmt * pmt -> pmt
| App : pmt * pmt -> pmt
| Deg : pmt * string -> pmt
| Asc : pmt * pmt -> pmt
| Lam : string * pmt -> pmt
| Struct : (string * pmt) list -> pmt
| Constr : string -> pmt
(* Using a Bwv of variable names, to turn them into De Bruijn indices, we can parse such a term into a synth/checkable one. *)
let rec parse_chk : type n. (string, n) Bwv.t -> pmt -> n Raw.check located =
fun ctx -> function
| Lam (x, body) ->
unlocated (Raw.Lam ({ value = Some x; loc = None }, `Normal, parse_chk (Snoc (ctx, x)) body))
| Struct tms ->
unlocated
(Raw.Struct
( Eta,
List.fold_left
(fun acc (fld, tm) -> Abwd.add (Some (Field.intern fld)) (parse_chk ctx tm) acc)
Abwd.empty tms ))
| Constr c -> unlocated (Raw.Constr (unlocated (Constr.intern c), []))
| App (fn, arg) as tm -> (
match (parse_chk ctx fn).value with
| Constr (c, args) ->
(* I would never grow a forwards list on the right in real code, but I can't be bothered to do the right thing in this old code that we should get rid of as soon as feasible. *)
unlocated (Raw.Constr (c, args @ [ parse_chk ctx arg ]))
| _ -> unlocated (Raw.Synth (parse_syn ctx tm).value))
| tm -> unlocated (Raw.Synth (parse_syn ctx tm).value)
and parse_syn : type n. (string, n) Bwv.t -> pmt -> n Raw.synth located =
fun ctx -> function
| Var x -> (
match Bwv.find_opt (fun y -> x = y) ctx with
| Some (_, v) -> unlocated (Raw.Var (v, None))
| None -> Reporter.fatal (Unbound_variable (x, [])))
| Const x -> (
match Scope.lookup [ x ] with
| Some c -> unlocated (Raw.Const c)
| None -> Reporter.fatal (Unbound_variable (x, [])))
| UU -> unlocated Raw.UU
| Field (x, fld) -> unlocated (Raw.Field (parse_syn ctx x, Field.intern_ori fld))
| Pi (x, dom, cod) ->
unlocated (Raw.Pi (Some x, parse_chk ctx dom, parse_chk (Snoc (ctx, x)) cod))
| App (fn, arg) -> unlocated (Raw.App (parse_syn ctx fn, parse_chk ctx arg))
| Deg (x, str) -> (
let x = (parse_chk ctx x).value in
match Dim.deg_of_name str with
| Some (Any s) -> unlocated (Raw.Act (str, s, unlocated x))
| None -> (
match Dim.deg_of_string str with
| Some (Any s) -> unlocated (Raw.Act (str, s, unlocated x))
| None -> raise (Failure "unknown degeneracy")))
| Asc (tm, ty) -> unlocated (Raw.Asc (parse_chk ctx tm, parse_chk ctx ty))
| _ -> raise (Failure "Non-synthesizing")
(* Nicer syntax, with a prefix operator for using a variable by name, and infix operators for abstraction, application, and ascription. *)
let ( !! ) x = Var x
let ( !~ ) x = Const x
let ( !. ) x = Constr x
(* let pi x dom cod = Pi (x, dom, cod) *)
let ( @=> ) (x, dom) cod = Pi (x, dom, cod)
let ( $ ) fn arg = App (fn, arg) (* Left-associative *)
let id a x y = App (App (Deg (a, "refl"), x), y)
let refl x = Deg (x, "refl")
let sym x = Deg (x, "sym")
let ( <:> ) tm ty = Asc (tm, ty)
let ( @-> ) x body = Lam (x, body) (* Right-associative *)
let ( $. ) x fld = Field (x, fld)
let struc tms = Struct tms
let ( $^ ) x s = Deg (x, s)
module Terminal = Asai.Tty.Make (Core.Reporter.Code)
(* The current context of assumptions, including names. *)
type ctx = Ctx : ('n, 'b) Ctx.t * (string, 'n) Bwv.t -> ctx
let ectx = Ctx (Ctx.empty, Emp)
let context = ref ectx
(* Functions to synth and check terms *)
let synth (tm : pmt) : kinetic value * kinetic value =
let (Ctx (ctx, names)) = !context in
Reporter.run ~emit:Terminal.display ~fatal:(fun d ->
Terminal.display d;
raise (Failure "Failed to synthesize"))
@@ fun () ->
let raw = parse_syn names tm in
let syn, ty = Check.synth (Kinetic `Nolet) ctx raw in
let esyn = eval_term (Ctx.env ctx) syn in
(esyn, ty)
let check (tm : pmt) (ty : kinetic value) : kinetic value =
let (Ctx (ctx, names)) = !context in
Reporter.run ~emit:Terminal.display ~fatal:(fun d ->
Terminal.display d;
raise (Failure "Failed to check"))
@@ fun () ->
let raw = parse_chk names tm in
let chk = Check.check (Kinetic `Nolet) ctx raw ty in
eval_term (Ctx.env ctx) chk
(* Assert that a term *doesn't* synthesize or check *)
let unsynth (tm : pmt) : unit =
let (Ctx (ctx, names)) = !context in
Reporter.run ~emit:Terminal.display ~fatal:(fun _ -> ()) @@ fun () ->
let raw = parse_syn names tm in
let _ = Check.synth (Kinetic `Nolet) ctx raw in
raise (Failure "Synthesis success")
let uncheck (tm : pmt) (ty : kinetic value) : unit =
let (Ctx (ctx, names)) = !context in
Reporter.run ~emit:Terminal.display ~fatal:(fun _ -> ()) @@ fun () ->
let raw = parse_chk names tm in
let _ = Check.check (Kinetic `Nolet) ctx raw ty in
raise (Failure "Checking success")
(* Add to the context of assumptions *)
let assume (x : string) (ty : kinetic value) : kinetic value =
let (Ctx (ctx, names)) = !context in
context := Ctx (Ctx.ext ctx (Some x) ty, Snoc (names, x));
fst (synth !!x)
(* Check that two terms are, or aren't, equal, at a type or synthesizing *)
let equal_at (tm1 : kinetic value) (tm2 : kinetic value) (ty : kinetic value) : unit =
let (Ctx (ctx, _)) = !context in
if Option.is_some (Equal.equal_at (Ctx.length ctx) tm1 tm2 ty) then ()
else raise (Failure "Unequal terms")
let unequal_at (tm1 : kinetic value) (tm2 : kinetic value) (ty : kinetic value) : unit =
let (Ctx (ctx, _)) = !context in
if Option.is_none (Equal.equal_at (Ctx.length ctx) tm1 tm2 ty) then ()
else raise (Failure "Equal terms")
let equal (tm1 : kinetic value) (tm2 : kinetic value) : unit =
let (Ctx (ctx, _)) = !context in
if Option.is_some (Equal.equal_val (Ctx.length ctx) tm1 tm2) then ()
else raise (Failure "Unequal terms")
let unequal (tm1 : kinetic value) (tm2 : kinetic value) : unit =
let (Ctx (ctx, _)) = !context in
if Option.is_none (Equal.equal_val (Ctx.length ctx) tm1 tm2) then ()
else raise (Failure "Equal terms")
(* Infix notation for applying values *)
let ( $$ ) (fn : kinetic value) (arg : kinetic value) : kinetic value =
Norm.apply_term fn (Dim.CubeOf.singleton arg)
let run f = Repl.run f