Source file combinators.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
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
open Rocqlib
open CErrors
open Util
open Termops
open EConstr
open Retyping
open Typing
open Inductiveops
module RelDecl = Context.Rel.Declaration
(** Telescope *)
type family = SPropF | PropF | TypeF
let family_of_sort_family = let open Sorts in function
| InSProp -> SPropF
| InProp -> PropF
| InSet | InType | InQSort -> TypeF
let get_sigmatypes sigma ~sort ~predsort =
let open EConstr in
let which, sigsort = match predsort, sort with
| SPropF, _ | _, SPropF ->
user_err Pp.(str "SProp arguments not supported by Program Fixpoint yet.")
| PropF, PropF -> "ex", PropF
| PropF, TypeF -> "sig", TypeF
| TypeF, (PropF|TypeF) -> "sigT", TypeF
in
let sigma, ty = Evd.fresh_global (Global.env ()) sigma (lib_ref ("core."^which^".type")) in
let uinstance = snd (destRef sigma ty) in
let intro = mkRef (lib_ref ("core."^which^".intro"), uinstance) in
let p1 = mkRef (lib_ref ("core."^which^".proj1"), uinstance) in
let p2 = mkRef (lib_ref ("core."^which^".proj2"), uinstance) in
sigma, ty, intro, p1, p2, sigsort
let rec telescope sigma l =
let open EConstr in
let open Vars in
match l with
| [] -> assert false
| [RelDecl.LocalAssum (n, t), _] ->
sigma, t, [RelDecl.LocalDef (n, mkRel 1, t)], mkRel 1
| (LocalAssum (n, t), tsort) :: tl ->
let sigma, ty, _tysort, tys, (k, constr) =
List.fold_left
(fun (sigma, ty, tysort, tys, (k, constr)) (decl,sort) ->
let t = RelDecl.get_type decl in
let pred = mkLambda (RelDecl.get_annot decl, t, ty) in
let sigma, ty, intro, p1, p2, sigsort = get_sigmatypes sigma ~predsort:tysort ~sort in
let sigty = mkApp (ty, [|t; pred|]) in
let intro = mkApp (intro, [|lift k t; lift k pred; mkRel k; constr|]) in
(sigma, sigty, sigsort, (pred, p1, p2) :: tys, (succ k, intro)))
(sigma, t, tsort, [], (2, mkRel 1)) tl
in
let sigma, last, subst = List.fold_right2
(fun (pred,p1,p2) (decl,_) (sigma, prev, subst) ->
let t = RelDecl.get_type decl in
let proj1 = applist (p1, [t; pred; prev]) in
let proj2 = applist (p2, [t; pred; prev]) in
(sigma, lift 1 proj2, RelDecl.(LocalDef (get_annot decl, proj1, t) :: subst)))
(List.rev tys) tl (sigma, mkRel 1, [])
in sigma, ty, (LocalDef (n, last, t) :: subst), constr
| (LocalDef (n, b, t), _) :: tl ->
let sigma, ty, subst, term = telescope sigma tl in
sigma, ty, (LocalDef (n, b, t) :: subst), lift 1 term
type telescope = {
telescope_type : EConstr.types;
telescope_value : EConstr.constr;
}
let telescope env sigma ctx =
let ctx, _ = List.fold_right_map (fun d env ->
let s = Retyping.get_sort_family_of env sigma (RelDecl.get_type d) in
let env = EConstr.push_rel d env in
(d, family_of_sort_family s), env) ctx env
in
let sigma, telescope_type, letcontext, telescope_value = telescope sigma ctx in
sigma, letcontext, { telescope_type; telescope_value }
(** Closure of a term according to its dependencies *)
let make_tuple env sigma (rterm,rty) lind =
assert (not (Vars.noccurn sigma lind rty));
let sigdata = build_sigma_type () in
let sigma, a = type_of ~refresh:true env sigma (mkRel lind) in
let a = Tacred.simpl env sigma a in
let na = Context.Rel.Declaration.get_annot (lookup_rel lind env) in
let rty = Vars.lift (1-lind) (Vars.liftn lind (lind+1) rty) in
let p = mkLambda (na, a, rty) in
let sigma, exist_term = Evd.fresh_global env sigma sigdata.intro in
let sigma, sig_term = Evd.fresh_global env sigma sigdata.typ in
sigma,
(applist(exist_term,[a;p;(mkRel lind);rterm]),
applist(sig_term,[a;p]))
let minimal_free_rels env sigma (c,cty) =
let cty_rels = free_rels sigma cty in
let cty' = Tacred.simpl env sigma cty in
let rels' = free_rels sigma cty' in
if Int.Set.subset cty_rels rels' then
(cty,cty_rels)
else
(cty',rels')
let minimal_free_rels_rec env sigma =
let rec minimalrec_free_rels_rec prev_rels (c,cty) =
let (cty,direct_rels) = minimal_free_rels env sigma (c,cty) in
let combined_rels = Int.Set.union prev_rels direct_rels in
let folder rels i = snd (minimalrec_free_rels_rec rels (c, get_type_of env sigma (mkRel i)))
in (cty, List.fold_left folder combined_rels (Int.Set.elements (Int.Set.diff direct_rels prev_rels)))
in minimalrec_free_rels_rec Int.Set.empty
(** [sig_clausal_form siglen ty]
Will explode [siglen] [sigT ]'s on [ty] (depending on the
type of ty), and return:
(1) a pattern, with meta-variables in it for various arguments,
which, when the metavariables are replaced with appropriate
terms, will have type [ty]
(2) an integer, which is the last argument - the one which we just
returned.
(3) a pattern, for the type of that last meta
(4) a typing for each patvar
WARNING: No checking is done to make sure that the
sigT's are actually there.
- Only homogeneous pairs are built i.e. pairs where all the
dependencies are of the same sort
[sig_clausal_form] proceeds as follows: the default tuple is
constructed by taking the tuple-type, exploding the first [tuplen]
[sigT]'s, and replacing at each step the binder in the
right-hand-type by a fresh metavariable. In addition, on the way
back out, we will construct the pattern for the tuple which uses
these meta-vars.
This gives us a pattern, which we use to match against the type of
[dflt]; if that fails, then against the S(TRONG)NF of that type. If
both fail, then we just cannot construct our tuple. If one of
those succeed, then we can construct our value easily - we just use
the tuple-pattern.
*)
let sig_clausal_form env sigma sort_of_ty siglen ty dflt =
let sigdata = build_sigma_type () in
let rec sigrec_clausal_form sigma siglen p_i =
if Int.equal siglen 0 then
let dflt_typ = Retyping.get_type_of env sigma dflt in
try
let sigma = Evarconv.unify_leq_delay env sigma dflt_typ p_i in
let sigma = Evarconv.solve_unif_constraints_with_heuristics env sigma in
sigma, dflt
with Evarconv.UnableToUnify _ ->
user_err Pp.(str "Cannot solve a unification problem.")
else
let (a,p_i_minus_1) = match Reductionops.whd_beta_stack env sigma p_i with
| (_sigT,[a;p]) -> (a, p)
| _ -> anomaly ~label:"sig_clausal_form" (Pp.str "should be a sigma type.") in
let sigma, ev = Evarutil.new_evar env sigma a in
let rty = Reductionops.beta_applist sigma (p_i_minus_1,[ev]) in
let sigma, tuple_tail = sigrec_clausal_form sigma (siglen-1) rty in
if EConstr.isEvar sigma ev then
user_err Pp.(str "Cannot solve a unification problem.")
else
let sigma, exist_term = Evd.fresh_global env sigma sigdata.intro in
sigma, applist(exist_term,[a;p_i_minus_1;ev;tuple_tail])
in
let sigma, scf = sigrec_clausal_form sigma siglen ty in
sigma, Evarutil.nf_evar sigma scf
(** [make_iterated_tuple env sigma default c ctype] retruns
To do this, we find the free (relative) references of the strong NF
of [c]'s type, gather them together in left-to-right order
(i.e. highest-numbered is farthest-left), and construct a big
iterated pair out of it. This only works when the references are
all themselves to members of [Set]s, because we use [sigT] to
construct the tuple.
Suppose now that our constructed tuple is of length [tuplen]. We
need also to construct a default value for the other branches of
the destructor. As default value, we take a tuple of the form
[existT [xn]Pn ?n (... existT [x2]P2 ?2 (existT [x1]P1 ?1 term))]
but for this we have to solve the following unification problem:
typ = cty[i1/?1;...;in/?n]
This is done by [sig_clausal_form].
*)
let make_iterated_tuple env sigma ~default c cty =
let (cty,rels) = minimal_free_rels_rec env sigma (c,cty) in
let sort_of_cty = get_sort_of env sigma cty in
let sorted_rels = Int.Set.elements rels in
let sigma, (telescope_value, telescope_type) =
List.fold_left (fun (sigma, t) -> make_tuple env sigma t) (sigma, (c,cty)) sorted_rels
in
assert (Vars.closed0 sigma telescope_type);
let n = List.length sorted_rels in
let sigma, dfltval = sig_clausal_form env sigma sort_of_cty n telescope_type default in
sigma, { telescope_value; telescope_type }, dfltval
(** [make_selector env sigma dirn c ind special default]]
constructs a case-split on [c] of type [ind], with the [dirn]-th
branch giving [special], and all the rest giving [default]. *)
let make_selector env sigma ~pos ~special ~default c ctype =
let IndType(indf,_) as indt =
try find_rectype env sigma ctype
with Not_found ->
user_err
Pp.(str "Cannot discriminate on inductive constructors with \
dependent types.") in
let (ind, _),_ = dest_ind_family indf in
let () = Tacred.check_privacy env ind in
let typ = Retyping.get_type_of env sigma default in
let (mib,mip) = Inductive.lookup_mind_specif env ind in
let deparsign = make_arity_signature env sigma true indf in
let p = it_mkLambda_or_LetIn typ deparsign in
let cstrs = get_constructors env indf in
let build_branch i =
let endpt = if Int.equal i pos then special else default in
let args = cstrs.(i-1).cs_args in
it_mkLambda_or_LetIn endpt args in
let brl =
List.map build_branch(List.interval 1 (Array.length mip.mind_consnames)) in
let rci = ERelevance.relevant in
let ci = make_case_info env ind RegularStyle in
Inductiveops.make_case_or_project env sigma indt ci (p, rci) c (Array.of_list brl)