forked from AU-COBRA/ConCert
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Ast.v
297 lines (263 loc) · 10.9 KB
/
Ast.v
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
(** * λsmart language definition *)
From MetaCoq.Template Require All.
From Coq Require Import String.
From Coq Require Import List.
From ConCert.Utils Require Import Env.
Import ListNotations.
Module BasicTC := MetaCoq.Common.BasicAst.
Import Ast.
(** Aliases *)
Definition ename := string.
Definition inductive := string.
Inductive type : Set :=
| tyInd : inductive -> type
| tyForall : ename -> type -> type
| tyApp : type -> type -> type
| tyVar : ename -> type
| tyRel : nat -> type
| tyArr : type -> type -> type.
Record pat := pConstr {pName : ename; pVars : list ename}.
(** ** λsmart AST *)
(** We have both named variables and de Bruijn indices.
Translation to MetaCoq requires indices, while named representation
is what we might get from the integration API. We can define relations
on type of expressions ensuring that either names are used, or indices,
but not both at the same time. *)
(** Note also that AST must be explicitly annotated with types.
This is required for the translation to MetaCoq. *)
Inductive expr : Set :=
| eRel : nat -> expr (* de Bruijn index *)
| eVar : ename -> expr (* named variables *)
| eLambda : ename -> type -> expr -> expr
| eTyLam : ename -> expr -> expr (* abstraction for types *)
| eLetIn : ename -> expr -> type -> expr -> expr
| eApp : expr -> expr -> expr
| eConstr : inductive -> ename -> expr
| eConst : ename -> expr
| eCase : (inductive * list type) (* type of discriminee and a list of parameters *) ->
type ->
expr (* discriminee *) ->
list (pat * expr) (* branches *) ->
expr
| eFix : ename (* of the fix *) -> ename (* of the arg *) ->
type (* of the arg *) -> type (* return type *) -> expr (* body *) -> expr
| eTy : type -> expr.
(** An induction principle that takes into account nested
occurrences of expressions in the list of branches for [eCase] *)
Definition expr_ind_case (P : expr -> Prop)
(Hrel : forall n : nat, P (eRel n))
(Hvar : forall n : ename, P (eVar n))
(Hlam :forall (n : ename) (t : type) (e : expr), P e -> P (eLambda n t e))
(HtyLam : forall (n : ename) (e : expr), P e -> P (eTyLam n e))
(Hletin : forall (n : ename) (e : expr),
P e -> forall (t : type) (e0 : expr), P e0 -> P (eLetIn n e t e0))
(Happ :forall e : expr, P e -> forall e0 : expr, P e0 -> P (eApp e e0))
(Hconstr :forall (i : inductive) (n : ename), P (eConstr i n))
(Hconst :forall n : ename, P (eConst n))
(Hcase : forall (p : inductive * list type) (t : type) (e : expr),
P e -> forall l : list (pat * expr), Forall (fun x => P (snd x)) l ->P (eCase p t e l))
(Hfix :forall (n n0 : ename) (t t0 : type) (e : expr), P e -> P (eFix n n0 t t0 e))
(Hty : forall t : type, P (eTy t)) :
forall e : expr, P e.
Proof.
refine (fix ind (e : expr) := _).
destruct e.
+ apply Hrel.
+ apply Hvar.
+ apply Hlam. apply ind.
+ apply HtyLam. apply ind.
+ apply Hletin; apply ind.
+ apply Happ; apply ind.
+ apply Hconstr.
+ apply Hconst.
+ apply Hcase. apply ind.
induction l.
* constructor.
* constructor. apply ind. apply IHl.
+ apply Hfix. apply ind.
+ apply Hty.
Defined.
Fixpoint iclosed_ty (n : nat) (ty : type) : bool :=
match ty with
| tyInd x => true
| tyForall v ty1 => iclosed_ty (1+n) ty1
| tyApp ty1 ty2 => iclosed_ty n ty1 && iclosed_ty n ty2
| tyVar _ => false
| tyRel i => Nat.ltb i n
| tyArr ty1 ty2 => iclosed_ty n ty1 && iclosed_ty n ty2
end.
Fixpoint iclosed_n (n : nat) (e : expr) : bool :=
match e with
| eRel i => Nat.ltb i n
| eVar x => false
| eLambda nm ty b => iclosed_ty n ty && iclosed_n (1+n) b
| eTyLam _ b => iclosed_n (1+n) b
| eLetIn nm e1 ty e2 => iclosed_ty n ty && iclosed_n n e1 && iclosed_n (1+n) e2
| eApp e1 e2 => iclosed_n n e1 && iclosed_n n e2
| eConstr x x0 => true
| eConst x => true
| eCase ii ty e bs =>
let bs'' := List.forallb
(fun x => iclosed_n (length ((fst x).(pVars)) + n) (snd x)) bs in
forallb (iclosed_ty n) (snd ii) && iclosed_ty n ty && iclosed_n n e && bs''
| eFix fixname nm ty1 ty2 e => iclosed_ty n ty1 && iclosed_ty n ty2 && iclosed_n (2+n) e
| eTy ty => iclosed_ty n ty
end.
Definition vars_to_apps acc vs :=
fold_left eApp vs acc.
Definition constr := (string * list (option ename * type))%type.
(** Global declarations. Will be extended to handle
declaration of constant, e.g. function definitions *)
Inductive global_dec :=
| gdInd : ename
-> nat (* num of params *)
-> list constr
-> bool (* set to [true] if it's a record *)
-> global_dec.
Definition global_env := list global_dec.
Fixpoint lookup {A} (l : list (string * A)) key : option A :=
match l with
| [] => None
| (key', v) :: xs => if eqb key' key then Some v else lookup xs key
end.
Fixpoint lookup_global (Σ : global_env) (key : ename) : option global_dec :=
match Σ with
| [] => None
| gdInd key' n v r :: xs => if eqb key' key then Some (gdInd key' n v r) else lookup_global xs key
end.
(** Looks up for the given inductive by name and if succeeds,
returns a list of constructors with corresponding arities *)
Definition resolve_inductive (Σ : global_env) (ind_name : ename)
: option (nat * list constr) :=
match (lookup_global Σ ind_name) with
| Some (gdInd n nparam cs _) => Some (nparam, cs)
| None => None
end.
Definition remove_proj (c : constr) := map snd (snd c).
(** Resolves the given constructor name to a corresponding position
in the list of constructors along with the constructor's arity *)
Definition resolve_constr (Σ : global_env) (ind_name constr_name : ename)
: option (nat * nat * list type) :=
match (resolve_inductive Σ ind_name) with
| Some n_cs =>
match lookup_with_ind (map (fun c => (fst c, remove_proj c)) (snd n_cs)) constr_name with
| Some v => Some (fst n_cs, fst v, snd v)
| None => None
end
| None => None
end.
Definition bump_indices (l : list (ename * nat)) (n : nat) :=
map (fun '(x,y) => (x, n+y)) l.
(** For a list of vars returns a list of pairs (var,number) where
the number is a position of the var counted from the end of the list.
E.g. number_vars ["x"; "y"; "z"] = [("x", 2); ("y", 1); ("z", 0)] *)
Definition number_vars (i : nat) (ns : list ename) : list (ename * nat) :=
combine ns (rev (seq i (length ns + i))).
Open Scope string.
Example number_vars_xyz : number_vars 0 ["x"; "y"; "z"] = [("x", 2); ("y", 1); ("z", 0)].
Proof. reflexivity. Qed.
(** ** Conversion from named representation to De Bruijn indices *)
(** Converting variable names to De Bruijn indices in types *)
Fixpoint indexify_type (l : list (ename * nat)) (ty : type) : type :=
match ty with
| tyInd i => tyInd i
| tyForall nm ty => tyForall nm (indexify_type ((nm,0) :: bump_indices l 1) ty)
| tyVar nm => match (lookup l nm) with
| None => (* NOTE: a workaround to make the function total *)
tyVar ("not a closed type")
| Some v => tyRel v
end
| tyRel i => tyRel i
| tyApp ty1 ty2 =>
tyApp (indexify_type l ty1) (indexify_type l ty2)
| tyArr ty1 ty2 =>
(* NOTE: we have to bump indices for the codomain,
since in Coq arrow also introduces a binder in a MetaCoq term.
So, this is purely an artifact of the translation to MetaCoq *)
(* tyArr (indexify_type l ty1) (indexify_type (bump_indices l 1) ty2) *)
tyArr (indexify_type l ty1) (indexify_type l ty2)
end.
(** Converting variable names to De Bruijn indices *)
Fixpoint indexify (l : list (ename * nat)) (e : expr) : expr :=
match e with
| eRel i => eRel i
| eVar nm =>
match (lookup l nm) with
| None => (* NOTE: a workaround to make the function total *)
eVar ("not a closed term")
| Some v => eRel v
end
| eLambda nm ty b =>
eLambda nm (indexify_type l ty) (indexify ((nm,0) :: bump_indices l 1) b)
| eTyLam nm b => eTyLam nm (indexify ((nm,0) :: bump_indices l 1) b)
| eLetIn nm e1 ty e2 =>
eLetIn nm (indexify l e1) (indexify_type l ty) (indexify ((nm, 0) :: bump_indices l 1) e2)
| eApp e1 e2 => eApp (indexify l e1) (indexify l e2)
| eConstr t i as e => e
| eConst nm as e => e
| eCase nm_i ty2 e bs =>
let (nm,tys) := nm_i in
eCase (nm,map (indexify_type l) tys)
(indexify_type l ty2) (indexify l e)
(map (fun p => (fst p, indexify (number_vars 0 (fst p).(pVars) ++
bump_indices l (length (fst p).(pVars))) (snd p))) bs)
| eFix nm vn ty1 ty2 b =>
(* NOTE: name of the fixpoint becomes an index as well *)
let l' := bump_indices l 2 in
let l'' := ((nm,1) :: (vn,0) :: l') in
eFix nm vn (indexify_type l ty1) (indexify_type l ty2) (indexify l'' b)
| eTy ty => eTy (indexify_type l ty)
end.
(** Lifting indices of type variables in types *)
Fixpoint lift_type_vars (n k : nat) (ty : type) : type :=
match ty with
| tyInd nm => tyInd nm
| tyForall nm ty => tyForall nm (lift_type_vars n (1+k) ty)
| tyVar nm => tyVar nm
| tyRel i => if Nat.leb k i then tyRel (n + i) else tyRel i
| tyApp ty1 ty2 =>
tyApp (lift_type_vars n k ty1) (lift_type_vars n k ty2)
| tyArr ty1 ty2 =>
tyArr (lift_type_vars n k ty1) (lift_type_vars n k ty2)
end.
(** ** Merging type and term De Bruijn indices *)
(** Merging De Bruijn indices of type variables corresponding to type
abstractions with lambda abstractions. We assume that the expressions
are in the prenex form, so type abstractions can only occur at
the outermost positions: [\\A => \\ B => ... \x => \y => t] *)
Fixpoint reindexify (n : nat) (e : expr) : expr :=
match e with
| eRel i => eRel i
| eVar nm => eVar ("Named variables are not supported")
| eLambda nm ty b =>
eLambda nm (lift_type_vars n 0 ty) (reindexify (1+n) b)
| eTyLam nm b =>
(* we do not increment [n] since we assume prenex form *)
eTyLam nm (reindexify n b)
| eLetIn nm e1 ty e2 =>
eLetIn nm (reindexify n e1) (lift_type_vars n 0 ty) (reindexify (1+n) e2)
| eApp e1 e2 => eApp (reindexify n e1) (reindexify n e2)
| eConstr t i as e => e
| eConst nm as e => e
| eCase nm_i ty2 e bs =>
let (nm, tys) := nm_i in
eCase (nm, map (lift_type_vars n 0) tys)
(lift_type_vars n 0 ty2) (reindexify n e)
(map (fun p => (fst p, reindexify (length (fst p).(pVars) + n) (snd p))) bs)
| eFix nm vn ty1 ty2 b =>
eFix nm vn (lift_type_vars n 0 ty1) (lift_type_vars n 0 ty2) (reindexify (2+n) b)
| eTy ty => eTy (lift_type_vars n 0 ty)
end.
Fixpoint decompose_inductive (ty : type) : option (ename * list type) :=
match ty with
| tyInd x => Some (x,[])
| tyForall nm ty => None
| tyApp ty1 ty2 =>
match decompose_inductive ty1 with
| Some res =>let '(ind, tys) := res in Some (ind, (tys++[ty2])%list)
| _ => None
end
| tyVar x => None
| tyRel x => None
| tyArr x x0 => None
end.