aboutsummaryrefslogtreecommitdiff
path: root/kernel/indtypes.ml
blob: 96fe8d5846c7937b8fdbdfb5dacd4365d174fd4d (plain)
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 = get_globals (context env);
    mind_packets = packets;
    mind_constraints = cst;
    mind_singl = None;
    mind_nparams = nparams }