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
|
(* $Id$ *)
open Util
open Generic
open Term
open Inductive
open Sign
open Environ
open Instantiate
open Reduction
(* In the following, each time an [evar_map] is required, then [Evd.empty]
is given, since inductive types are typed in an environment without
existentials. *)
let mind_check_arities env mie =
let check_arity id c =
if not (is_arity env Evd.empty c) then
raise (InductiveError (NotAnArity id))
in
List.iter (fun (id,ar,_,_) -> check_arity id ar) mie.mind_entry_inds
let sort_of_arity env c =
let rec sort_of ar =
match whd_betadeltaiota env Evd.empty ar with
| DOP0 (Sort s) -> s
| DOP2 (Prod, _, DLAM (_, c)) -> sort_of c
| _ -> error "not an arity"
in
sort_of c
let allowed_sorts issmall isunit = function
| Type _ ->
[prop;spec;types]
| Prop Pos ->
if issmall then [prop;spec;types] else [prop;spec]
| Prop Null ->
if isunit then [prop;spec] else [prop]
let is_small_type t = is_small t.typ
let failwith_non_pos_vect n ntypes v =
for i = 0 to Array.length v - 1 do
for k = n to n + ntypes - 1 do
if not (noccurn k v.(i)) then raise (InductiveError (NonPos (k-n+1)))
done
done;
anomaly "failwith_non_pos_vect: some k in [n;n+ntypes-1] should occur in v"
let check_correct_par env nparams ntypes n l largs =
if Array.length largs < nparams then raise (InductiveError (NotEnoughArgs l));
let (lpar,largs') = array_chop nparams largs in
for k = 0 to nparams - 1 do
if not ((Rel (n-k-1))= whd_betadeltaiotaeta env Evd.empty lpar.(k)) then
raise (InductiveError (NonPar (k+1,l)))
done;
if not (array_for_all (noccur_bet n ntypes) largs') then
failwith_non_pos_vect n ntypes largs'
let abstract_mind_lc env ntyps npars lc =
let lC = decomp_DLAMV ntyps lc in
if npars = 0 then
lC
else
let make_abs =
list_tabulate
(function i -> lambda_implicit_lift npars (Rel (i+1))) ntyps
in
Array.map (compose (nf_beta env Evd.empty) (substl make_abs)) lC
let decomp_par n c = snd (decompose_prod_n n c)
let listrec_mconstr env ntypes nparams i indlc =
(* check the inductive types occur positively in C *)
let rec check_pos n c =
match whd_betadeltaiota env Evd.empty c with
| DOP2(Prod,b,DLAM(na,d)) ->
if not (noccur_bet n ntypes b) then raise (InductiveError (NonPos n));
check_pos (n+1) d
| x ->
(match ensure_appl x with
| DOPN(AppL,cl) ->
let hd = array_hd cl
and largs = array_tl cl in
(match hd with
| Rel k ->
check_correct_par env nparams ntypes n (k-n+1) largs;
if k >= n && k<n+ntypes then
Mrec(n+ntypes-k-1)
else if noccur_bet n ntypes x then
if (n-nparams) <= k & k <= (n-1)
then Param(n-1-k)
else Norec
else
raise (InductiveError (NonPos n))
| (DOPN(MutInd(sp,i),_) as mi) ->
if (noccur_bet n ntypes x) then
Norec
else
Imbr(sp,i,imbr_positive n mi largs)
| err ->
if noccur_bet n ntypes x then Norec
else raise (InductiveError (NonPos n)))
| _ -> anomaly "check_pos")
and imbr_positive n mi largs =
let mispeci = lookup_mind_specif mi env in
let auxnpar = mis_nparams mispeci in
let (lpar,auxlargs) = array_chop auxnpar largs in
if not (array_for_all (noccur_bet n ntypes) auxlargs) then
raise (InductiveError (NonPos n));
let auxlc = mis_lc mispeci
and auxntyp = mis_ntypes mispeci in
if auxntyp <> 1 then raise (InductiveError (NonPos n));
let lrecargs = array_map_to_list (check_param_pos n) lpar in
(* The abstract imbricated inductive type with parameters substituted *)
let auxlcvect = abstract_mind_lc env auxntyp auxnpar auxlc in
let newidx = n + auxntyp in
let _ =
(* fails if the inductive type occurs non positively *)
(* when substituted *)
Array.map
(function c ->
let c' = hnf_prod_appvect env Evd.empty "is_imbr_pos" c
(Array.map (lift auxntyp) lpar) in
check_construct false newidx c')
auxlcvect
in
lrecargs
(* The function check_param_pos is exactly the same as check_pos, but
with an extra case for traversing abstractions, like in Marseille's
contribution about bisimulations:
CoInductive strong_eq:process->process->Prop:=
str_eq:(p,q:process)((a:action)(p':process)(transition p a p')->
(Ex [q':process] (transition q a q')/\(strong_eq p' q')))->
((a:action)(q':process)(transition q a q')->
(Ex [p':process] (transition p a p')/\(strong_eq p' q')))->
(strong_eq p q).
Abstractions may occur in imbricated recursive ocurrences, but I am
not sure if they make sense in a form of constructor. This is why I
chose to duplicated the code. Eduardo 13/7/99. *)
and check_param_pos n c =
match whd_betadeltaiota env Evd.empty c with
(* The extra case *)
| DOP2(Lambda,b,DLAM(na,d)) ->
if noccur_bet n ntypes b
then check_param_pos (n+1) d
else raise (InductiveError (NonPos n))
(******************)
| DOP2(Prod,b,DLAM(na,d)) ->
if (noccur_bet n ntypes b)
then check_param_pos (n+1) d
else raise (InductiveError (NonPos n))
| x ->
(match ensure_appl x with
| DOPN(AppL,cl) ->
let hd = array_hd cl
and largs = array_tl cl in
(match hd with
| Rel k ->
check_correct_par env nparams ntypes n (k-n+1) largs;
if k >= n & k<n+ntypes then
Mrec(n+ntypes-k-1)
else if noccur_bet n ntypes x then
if (n-nparams) <= k & k <= (n-1)
then Param(n-1-k)
else Norec
else raise (InductiveError (NonPos n))
| (DOPN(MutInd(sp,i),_) as mi) ->
if (noccur_bet n ntypes x)
then Norec
else Imbr(sp,i,imbr_positive n mi largs)
| err -> if noccur_bet n ntypes x then Norec
else raise (InductiveError (NonPos n)))
| _ -> anomaly "check_param_pos")
(* check the inductive types occur positively in the products of C, if
checkhd=true, also check the head corresponds to a constructor of
the ith type *)
and check_construct check =
let rec check_constr_rec lrec n c =
match whd_betadeltaiota env Evd.empty c with
| DOP2(Prod,b,DLAM(na,d)) ->
let recarg = (check_pos n b) in
check_constr_rec (recarg::lrec) (n+1) d
| x ->
(match ensure_appl x with
| DOPN(AppL,cl) ->
let hd = array_hd cl
and largs = array_tl cl in
if check then
(match hd with
| Rel k ->
check_correct_par env nparams ntypes n (k-n+1) largs;
if k = n+ntypes-i then
List.rev lrec
else
raise (InductiveError (NonPos n))
| _ -> raise (InductiveError (NonPos n)))
else
if array_for_all (noccur_bet n ntypes) largs
then List.rev lrec
else raise (InductiveError (NonPos n))
| _ -> anomaly "ensure_appl should return an AppL")
in check_constr_rec []
in
let (lna,lC) = decomp_DLAMV_name ntypes indlc in
Array.map
(fun c ->
(* try *)
check_construct true (1+nparams) (decomp_par nparams c)
(* with InductiveError err ->
explain_ind_err (ntypes-i+1) lna nparams c err *))
lC
let is_recursive listind =
let rec one_is_rec rvec =
List.exists (function Mrec(i) -> List.mem i listind
| Imbr(_,_,lvec) -> one_is_rec lvec
| Norec -> false
| Param _ -> false) rvec
in
array_exists one_is_rec
let cci_inductive env env_ar kind nparams finite inds cst =
let ntypes = List.length inds in
let one_packet i (id,ar,cnames,issmall,isunit,lc) =
let recargs = listrec_mconstr env_ar ntypes nparams i lc in
let isunit = isunit && ntypes = 1 && (not (is_recursive [0] recargs)) in
let kelim = allowed_sorts issmall isunit (sort_of_arity env ar.body) in
{ mind_consnames = Array.of_list cnames;
mind_typename = id;
mind_lc = lc;
mind_arity = ar;
mind_kelim = kelim;
mind_listrec = recargs;
mind_finite = finite }
in
let packets = Array.of_list (list_map_i one_packet 1 inds) in
{ mind_kind = kind;
mind_ntypes = ntypes;
mind_hyps = var_context env;
mind_packets = packets;
mind_constraints = cst;
mind_singl = None;
mind_nparams = nparams }
|