~ubuntu-branches/ubuntu/wily/coq-doc/wily

« back to all changes in this revision

Viewing changes to checker/term.ml

  • Committer: Bazaar Package Importer
  • Author(s): Stéphane Glondu, Stéphane Glondu, Samuel Mimram
  • Date: 2010-01-07 22:50:39 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20100107225039-n3cq82589u0qt0s2
Tags: 8.2pl1-1
[ Stéphane Glondu ]
* New upstream release (Closes: #563669)
  - remove patches
* Packaging overhaul:
  - use git, advertise it in Vcs-* fields of debian/control
  - use debhelper 7 and dh with override
  - use source format 3.0 (quilt)
* debian/control:
  - set Maintainer to d-o-m, set Uploaders to Sam and myself
  - add Homepage field
  - bump Standards-Version to 3.8.3
* Register PDF documentation into doc-base
* Add debian/watch
* Update debian/copyright

[ Samuel Mimram ]
* Change coq-doc's description to mention that it provides documentation in
  pdf format, not postscript, closes: #543545.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(************************************************************************)
 
2
(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
 
3
(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
 
4
(*   \VV/  **************************************************************)
 
5
(*    //   *      This file is distributed under the terms of the       *)
 
6
(*         *       GNU Lesser General Public License Version 2.1        *)
 
7
(************************************************************************)
 
8
 
 
9
(* $Id: term.ml 10098 2007-08-27 11:41:08Z herbelin $ *)
 
10
 
 
11
(* This module instantiates the structure of generic deBruijn terms to Coq *)
 
12
 
 
13
open Util
 
14
open Pp
 
15
open Names
 
16
open Univ
 
17
open Esubst
 
18
open Validate
 
19
 
 
20
(* Coq abstract syntax with deBruijn variables; 'a is the type of sorts *)
 
21
 
 
22
type existential_key = int
 
23
type metavariable = int
 
24
 
 
25
(* This defines the strategy to use for verifiying a Cast *)
 
26
 
 
27
(* This defines Cases annotations *)
 
28
type case_style = LetStyle | IfStyle | LetPatternStyle | MatchStyle |
 
29
  RegularStyle
 
30
type case_printing =
 
31
  { ind_nargs : int; (* number of real args of the inductive type *)
 
32
    style     : case_style }
 
33
type case_info =
 
34
  { ci_ind        : inductive;
 
35
    ci_npar       : int;
 
36
    ci_cstr_nargs : int array; (* number of real args of each constructor *)
 
37
    ci_pp_info    : case_printing (* not interpreted by the kernel *)
 
38
  }
 
39
let val_ci =
 
40
  let val_cstyle = val_enum "case_style" 5 in
 
41
  let val_cprint = val_tuple "case_printing" [|val_int;val_cstyle|] in
 
42
  val_tuple "case_info" [|val_ind;val_int;val_array val_int;val_cprint|]
 
43
 
 
44
(* Sorts. *)
 
45
 
 
46
type contents = Pos | Null
 
47
 
 
48
type sorts =
 
49
  | Prop of contents                      (* proposition types *)
 
50
  | Type of universe
 
51
 
 
52
type sorts_family = InProp | InSet | InType
 
53
 
 
54
let family_of_sort = function
 
55
  | Prop Null -> InProp
 
56
  | Prop Pos -> InSet
 
57
  | Type _ -> InType
 
58
 
 
59
let val_sort = val_sum "sort" 0 [|[|val_enum "cnt" 2|];[|val_univ|]|]
 
60
let val_sortfam = val_enum "sorts_family" 3
 
61
 
 
62
(********************************************************************)
 
63
(*       Constructions as implemented                               *)
 
64
(********************************************************************)
 
65
 
 
66
(* [constr array] is an instance matching definitional [named_context] in
 
67
   the same order (i.e. last argument first) *)
 
68
type 'constr pexistential = existential_key * 'constr array
 
69
type 'constr prec_declaration =
 
70
    name array * 'constr array * 'constr array
 
71
type 'constr pfixpoint =
 
72
    (int array * int) * 'constr prec_declaration
 
73
type 'constr pcofixpoint =
 
74
    int * 'constr prec_declaration
 
75
 
 
76
let val_evar f = val_tuple "pexistential" [|val_int;val_array f|]
 
77
let val_prec f =
 
78
  val_tuple "prec_declaration"[|val_array val_name; val_array f; val_array f|]
 
79
let val_fix f =
 
80
  val_tuple"pfixpoint"
 
81
    [|val_tuple"fix2"[|val_array val_int;val_int|];val_prec f|]
 
82
let val_cofix f = val_tuple"pcofixpoint"[|val_int;val_prec f|]
 
83
 
 
84
type cast_kind = VMcast | DEFAULTcast 
 
85
let val_cast = val_enum "cast_kind" 2
 
86
 
 
87
(*s*******************************************************************)
 
88
(* The type of constructions *)
 
89
 
 
90
type constr =
 
91
  | Rel       of int
 
92
  | Var       of identifier
 
93
  | Meta      of metavariable
 
94
  | Evar      of constr pexistential
 
95
  | Sort      of sorts
 
96
  | Cast      of constr * cast_kind * constr
 
97
  | Prod      of name * constr * constr
 
98
  | Lambda    of name * constr * constr
 
99
  | LetIn     of name * constr * constr * constr
 
100
  | App       of constr * constr array
 
101
  | Const     of constant
 
102
  | Ind       of inductive
 
103
  | Construct of constructor
 
104
  | Case      of case_info * constr * constr * constr array
 
105
  | Fix       of constr pfixpoint
 
106
  | CoFix     of constr pcofixpoint
 
107
 
 
108
let val_constr = val_rec_sum "constr" 0 (fun val_constr -> [|
 
109
  [|val_int|]; (* Rel *)
 
110
  [|val_id|]; (* Var *)
 
111
  [|val_int|]; (* Meta *)
 
112
  [|val_evar val_constr|]; (* Evar *)
 
113
  [|val_sort|]; (* Sort *)
 
114
  [|val_constr;val_cast;val_constr|]; (* Cast *)
 
115
  [|val_name;val_constr;val_constr|]; (* Prod *)
 
116
  [|val_name;val_constr;val_constr|]; (* Lambda *)
 
117
  [|val_name;val_constr;val_constr;val_constr|]; (* LetIn *)
 
118
  [|val_constr;val_array val_constr|]; (* App *)
 
119
  [|val_kn|]; (* Const *)
 
120
  [|val_ind|]; (* Ind *)
 
121
  [|val_cstr|]; (* Construct *)
 
122
  [|val_ci;val_constr;val_constr;val_array val_constr|]; (* Case *)
 
123
  [|val_fix val_constr|]; (* Fix *)
 
124
  [|val_cofix val_constr|] (* CoFix *)
 
125
|])
 
126
 
 
127
type existential = constr pexistential
 
128
type rec_declaration = constr prec_declaration
 
129
type fixpoint = constr pfixpoint
 
130
type cofixpoint = constr pcofixpoint
 
131
 
 
132
 
 
133
let rec strip_outer_cast c = match c with
 
134
  | Cast (c,_,_) -> strip_outer_cast c
 
135
  | _ -> c
 
136
 
 
137
let rec collapse_appl c = match c with
 
138
  | App (f,cl) -> 
 
139
      let rec collapse_rec f cl2 =
 
140
        match (strip_outer_cast f) with
 
141
        | App (g,cl1) -> collapse_rec g (Array.append cl1 cl2)
 
142
        | _ -> App (f,cl2)
 
143
      in
 
144
      collapse_rec f cl
 
145
  | _ -> c
 
146
 
 
147
let decompose_app c =
 
148
  match collapse_appl c with
 
149
    | App (f,cl) -> (f, Array.to_list cl)
 
150
    | _ -> (c,[])
 
151
 
 
152
 
 
153
let applist (f,l) = App (f, Array.of_list l)
 
154
 
 
155
 
 
156
(****************************************************************************)
 
157
(*              Functions for dealing with constr terms                     *)
 
158
(****************************************************************************)
 
159
 
 
160
(*********************)
 
161
(*     Occurring     *)
 
162
(*********************)
 
163
 
 
164
let iter_constr_with_binders g f n c = match c with
 
165
  | (Rel _ | Meta _ | Var _   | Sort _ | Const _ | Ind _
 
166
    | Construct _) -> ()
 
167
  | Cast (c,_,t) -> f n c; f n t
 
168
  | Prod (_,t,c) -> f n t; f (g n) c
 
169
  | Lambda (_,t,c) -> f n t; f (g n) c
 
170
  | LetIn (_,b,t,c) -> f n b; f n t; f (g n) c
 
171
  | App (c,l) -> f n c; Array.iter (f n) l
 
172
  | Evar (_,l) -> Array.iter (f n) l
 
173
  | Case (_,p,c,bl) -> f n p; f n c; Array.iter (f n) bl
 
174
  | Fix (_,(_,tl,bl)) -> 
 
175
      Array.iter (f n) tl;
 
176
      Array.iter (f (iterate g (Array.length tl) n)) bl
 
177
  | CoFix (_,(_,tl,bl)) ->
 
178
      Array.iter (f n) tl;
 
179
      Array.iter (f (iterate g (Array.length tl) n)) bl
 
180
 
 
181
exception LocalOccur
 
182
 
 
183
(* (closedn n M) raises FreeVar if a variable of height greater than n
 
184
   occurs in M, returns () otherwise *)
 
185
 
 
186
let closedn n c = 
 
187
  let rec closed_rec n c = match c with
 
188
    | Rel m -> if m>n then raise LocalOccur
 
189
    | _ -> iter_constr_with_binders succ closed_rec n c
 
190
  in 
 
191
  try closed_rec n c; true with LocalOccur -> false
 
192
 
 
193
(* [closed0 M] is true iff [M] is a (deBruijn) closed term *)
 
194
 
 
195
let closed0 = closedn 0
 
196
 
 
197
(* (noccurn n M) returns true iff (Rel n) does NOT occur in term M  *)
 
198
 
 
199
let noccurn n term = 
 
200
  let rec occur_rec n c = match c with
 
201
    | Rel m -> if m = n then raise LocalOccur
 
202
    | _ -> iter_constr_with_binders succ occur_rec n c
 
203
  in 
 
204
  try occur_rec n term; true with LocalOccur -> false
 
205
 
 
206
(* (noccur_between n m M) returns true iff (Rel p) does NOT occur in term M 
 
207
  for n <= p < n+m *)
 
208
 
 
209
let noccur_between n m term = 
 
210
  let rec occur_rec n c = match c with
 
211
    | Rel(p) -> if n<=p && p<n+m then raise LocalOccur
 
212
    | _        -> iter_constr_with_binders succ occur_rec n c
 
213
  in 
 
214
  try occur_rec n term; true with LocalOccur -> false
 
215
 
 
216
(* Checking function for terms containing existential variables.
 
217
 The function [noccur_with_meta] considers the fact that
 
218
 each existential variable (as well as each isevar)
 
219
 in the term appears applied to its local context,
 
220
 which may contain the CoFix variables. These occurrences of CoFix variables
 
221
 are not considered *)
 
222
 
 
223
let noccur_with_meta n m term = 
 
224
  let rec occur_rec n c = match c with
 
225
    | Rel p -> if n<=p & p<n+m then raise LocalOccur
 
226
    | App(f,cl) ->
 
227
        (match f with
 
228
           | (Cast (Meta _,_,_)| Meta _) -> ()
 
229
           | _ -> iter_constr_with_binders succ occur_rec n c)
 
230
    | Evar (_, _) -> ()
 
231
    | _ -> iter_constr_with_binders succ occur_rec n c
 
232
  in
 
233
  try (occur_rec n term; true) with LocalOccur -> false
 
234
 
 
235
 
 
236
(*********************)
 
237
(*      Lifting      *)
 
238
(*********************)
 
239
 
 
240
let map_constr_with_binders g f l c = match c with
 
241
  | (Rel _ | Meta _ | Var _   | Sort _ | Const _ | Ind _
 
242
    | Construct _) -> c
 
243
  | Cast (c,k,t) -> Cast (f l c, k, f l t)
 
244
  | Prod (na,t,c) -> Prod (na, f l t, f (g l) c)
 
245
  | Lambda (na,t,c) -> Lambda (na, f l t, f (g l) c)
 
246
  | LetIn (na,b,t,c) -> LetIn (na, f l b, f l t, f (g l) c)
 
247
  | App (c,al) -> App (f l c, Array.map (f l) al)
 
248
  | Evar (e,al) -> Evar (e, Array.map (f l) al)
 
249
  | Case (ci,p,c,bl) -> Case (ci, f l p, f l c, Array.map (f l) bl)
 
250
  | Fix (ln,(lna,tl,bl)) ->
 
251
      let l' = iterate g (Array.length tl) l in
 
252
      Fix (ln,(lna,Array.map (f l) tl,Array.map (f l') bl))
 
253
  | CoFix(ln,(lna,tl,bl)) ->
 
254
      let l' = iterate g (Array.length tl) l in
 
255
      CoFix (ln,(lna,Array.map (f l) tl,Array.map (f l') bl))
 
256
 
 
257
(* The generic lifting function *)
 
258
let rec exliftn el c = match c with
 
259
  | Rel i -> Rel(reloc_rel i el)
 
260
  | _ -> map_constr_with_binders el_lift exliftn el c
 
261
 
 
262
(* Lifting the binding depth across k bindings *)
 
263
 
 
264
let liftn k n = 
 
265
  match el_liftn (pred n) (el_shft k ELID) with
 
266
    | ELID -> (fun c -> c)
 
267
    | el -> exliftn el
 
268
 
 
269
let lift k = liftn k 1
 
270
 
 
271
(*********************)
 
272
(*   Substituting    *)
 
273
(*********************)
 
274
 
 
275
(* (subst1 M c) substitutes M for Rel(1) in c 
 
276
   we generalise it to (substl [M1,...,Mn] c) which substitutes in parallel
 
277
   M1,...,Mn for respectively Rel(1),...,Rel(n) in c *)
 
278
 
 
279
(* 1st : general case *)
 
280
type info = Closed | Open | Unknown
 
281
type 'a substituend = { mutable sinfo: info; sit: 'a }
 
282
 
 
283
let rec lift_substituend depth s =
 
284
  match s.sinfo with
 
285
    | Closed -> s.sit
 
286
    | Open -> lift depth s.sit
 
287
    | Unknown ->
 
288
        s.sinfo <- if closed0 s.sit then Closed else Open;
 
289
        lift_substituend depth s
 
290
 
 
291
let make_substituend c = { sinfo=Unknown; sit=c }
 
292
 
 
293
let substn_many lamv n c =
 
294
  let lv = Array.length lamv in 
 
295
  if lv = 0 then c
 
296
  else 
 
297
    let rec substrec depth c = match c with
 
298
      | Rel k     ->
 
299
          if k<=depth then c
 
300
          else if k-depth <= lv then lift_substituend depth lamv.(k-depth-1)
 
301
          else Rel (k-lv)
 
302
      | _ -> map_constr_with_binders succ substrec depth c in 
 
303
    substrec n c
 
304
 
 
305
let substnl laml n =
 
306
  substn_many (Array.map make_substituend (Array.of_list laml)) n
 
307
let substl laml = substnl laml 0
 
308
let subst1 lam = substl [lam]
 
309
 
 
310
 
 
311
(***************************************************************************)
 
312
(*     Type of assumptions and contexts                                    *)
 
313
(***************************************************************************)
 
314
 
 
315
let val_ndecl =
 
316
  val_tuple"named_declaration"[|val_id;val_opt val_constr;val_constr|]
 
317
let val_rdecl =
 
318
  val_tuple"rel_declaration"[|val_name;val_opt val_constr;val_constr|]
 
319
let val_nctxt = val_list val_ndecl
 
320
let val_rctxt = val_list val_rdecl
 
321
 
 
322
type named_declaration = identifier * constr option * constr
 
323
type rel_declaration = name * constr option * constr
 
324
 
 
325
let map_named_declaration f (id, v, ty) = (id, Option.map f v, f ty)
 
326
let map_rel_declaration = map_named_declaration
 
327
 
 
328
let fold_named_declaration f (_, v, ty) a = f ty (Option.fold_right f v a)
 
329
let fold_rel_declaration = fold_named_declaration
 
330
 
 
331
 
 
332
type named_context = named_declaration list
 
333
let empty_named_context = []
 
334
let fold_named_context f l ~init = List.fold_right f l init
 
335
 
 
336
type section_context = named_context
 
337
 
 
338
type rel_context = rel_declaration list
 
339
let empty_rel_context = []
 
340
let rel_context_length = List.length
 
341
let rel_context_nhyps hyps =
 
342
  let rec nhyps acc = function
 
343
    | [] -> acc
 
344
    | (_,None,_)::hyps -> nhyps (1+acc) hyps
 
345
    | (_,Some _,_)::hyps -> nhyps acc hyps in
 
346
  nhyps 0 hyps
 
347
let fold_rel_context f l ~init = List.fold_right f l init
 
348
 
 
349
let map_context f l =
 
350
  let map_decl (n, body_o, typ as decl) =
 
351
    let body_o' = Option.smartmap f body_o in
 
352
    let typ' = f typ in
 
353
      if body_o' == body_o && typ' == typ then decl else
 
354
        (n, body_o', typ')
 
355
  in
 
356
    list_smartmap map_decl l
 
357
 
 
358
let map_rel_context = map_context
 
359
 
 
360
let extended_rel_list n hyps =
 
361
  let rec reln l p = function
 
362
    | (_,None,_) :: hyps -> reln (Rel (n+p) :: l) (p+1) hyps
 
363
    | (_,Some _,_) :: hyps -> reln l (p+1) hyps
 
364
    | [] -> l
 
365
  in 
 
366
  reln [] 1 hyps
 
367
 
 
368
(* Iterate lambda abstractions *)
 
369
 
 
370
(* compose_lam [xn:Tn;..;x1:T1] b = [x1:T1]..[xn:Tn]b *)
 
371
let compose_lam l b =
 
372
  let rec lamrec = function
 
373
    | ([], b)       -> b
 
374
    | ((v,t)::l, b) -> lamrec (l, Lambda (v,t,b))
 
375
  in 
 
376
  lamrec (l,b)
 
377
 
 
378
(* Transforms a lambda term [x1:T1]..[xn:Tn]T into the pair
 
379
   ([(xn,Tn);...;(x1,T1)],T), where T is not a lambda *)
 
380
let decompose_lam = 
 
381
  let rec lamdec_rec l c = match c with
 
382
    | Lambda (x,t,c) -> lamdec_rec ((x,t)::l) c
 
383
    | Cast (c,_,_)     -> lamdec_rec l c
 
384
    | _                -> l,c
 
385
  in 
 
386
  lamdec_rec []
 
387
 
 
388
(* Decompose lambda abstractions and lets, until finding n
 
389
  abstractions *)
 
390
let decompose_lam_n_assum n =
 
391
  if n < 0 then
 
392
    error "decompose_lam_n_assum: integer parameter must be positive";
 
393
  let rec lamdec_rec l n c = 
 
394
    if n=0 then l,c 
 
395
    else match c with 
 
396
    | Lambda (x,t,c)  -> lamdec_rec ((x,None,t) :: l) (n-1) c
 
397
    | LetIn (x,b,t,c) -> lamdec_rec ((x,Some b,t) :: l) n c
 
398
    | Cast (c,_,_)      -> lamdec_rec l n c
 
399
    | c -> error "decompose_lam_n_assum: not enough abstractions"
 
400
  in 
 
401
  lamdec_rec empty_rel_context n 
 
402
 
 
403
(* Iterate products, with or without lets *)
 
404
 
 
405
(* Constructs either [(x:t)c] or [[x=b:t]c] *)
 
406
let mkProd_or_LetIn (na,body,t) c =
 
407
  match body with
 
408
    | None -> Prod (na, t, c)
 
409
    | Some b -> LetIn (na, b, t, c)
 
410
 
 
411
let it_mkProd_or_LetIn   = List.fold_left (fun c d -> mkProd_or_LetIn d c)
 
412
 
 
413
let decompose_prod_assum = 
 
414
  let rec prodec_rec l c =
 
415
    match c with
 
416
    | Prod (x,t,c)    -> prodec_rec ((x,None,t) :: l) c
 
417
    | LetIn (x,b,t,c) -> prodec_rec ((x,Some b,t) :: l) c
 
418
    | Cast (c,_,_)    -> prodec_rec l c
 
419
    | _               -> l,c
 
420
  in 
 
421
  prodec_rec empty_rel_context
 
422
 
 
423
let decompose_prod_n_assum n =
 
424
  if n < 0 then
 
425
    error "decompose_prod_n_assum: integer parameter must be positive";
 
426
  let rec prodec_rec l n c = 
 
427
    if n=0 then l,c
 
428
    else match c with 
 
429
    | Prod (x,t,c)    -> prodec_rec ((x,None,t) :: l) (n-1) c
 
430
    | LetIn (x,b,t,c) -> prodec_rec ((x,Some b,t) :: l) (n-1) c
 
431
    | Cast (c,_,_)    -> prodec_rec l n c
 
432
    | c -> error "decompose_prod_n_assum: not enough assumptions"
 
433
  in 
 
434
  prodec_rec empty_rel_context n
 
435
 
 
436
 
 
437
(***************************)
 
438
(* Other term constructors *)
 
439
(***************************)
 
440
 
 
441
type arity = rel_context * sorts
 
442
let val_arity = val_tuple"arity"[|val_rctxt;val_constr|]
 
443
 
 
444
let mkArity (sign,s) = it_mkProd_or_LetIn (Sort s) sign
 
445
 
 
446
let destArity = 
 
447
  let rec prodec_rec l c =
 
448
    match c with
 
449
    | Prod (x,t,c)    -> prodec_rec ((x,None,t)::l) c
 
450
    | LetIn (x,b,t,c) -> prodec_rec ((x,Some b,t)::l) c
 
451
    | Cast (c,_,_)    -> prodec_rec l c
 
452
    | Sort s          -> l,s
 
453
    | _               -> anomaly "destArity: not an arity"
 
454
  in 
 
455
  prodec_rec []
 
456
 
 
457
let rec isArity c =
 
458
  match c with
 
459
  | Prod (_,_,c)    -> isArity c
 
460
  | LetIn (_,b,_,c) -> isArity (subst1 b c)
 
461
  | Cast (c,_,_)    -> isArity c
 
462
  | Sort _          -> true
 
463
  | _               -> false
 
464
 
 
465
(*******************************)
 
466
(*  alpha conversion functions *)                         
 
467
(*******************************)
 
468
 
 
469
(* alpha conversion : ignore print names and casts *)
 
470
 
 
471
let compare_constr f t1 t2 =
 
472
  match t1, t2 with
 
473
  | Rel n1, Rel n2 -> n1 = n2
 
474
  | Meta m1, Meta m2 -> m1 = m2
 
475
  | Var id1, Var id2 -> id1 = id2
 
476
  | Sort s1, Sort s2 -> s1 = s2
 
477
  | Cast (c1,_,_), _ -> f c1 t2
 
478
  | _, Cast (c2,_,_) -> f t1 c2
 
479
  | Prod (_,t1,c1), Prod (_,t2,c2) -> f t1 t2 & f c1 c2
 
480
  | Lambda (_,t1,c1), Lambda (_,t2,c2) -> f t1 t2 & f c1 c2
 
481
  | LetIn (_,b1,t1,c1), LetIn (_,b2,t2,c2) -> f b1 b2 & f t1 t2 & f c1 c2
 
482
  | App (c1,l1), App (c2,l2) ->
 
483
      if Array.length l1 = Array.length l2 then
 
484
        f c1 c2 & array_for_all2 f l1 l2
 
485
      else
 
486
        let (h1,l1) = decompose_app t1 in        
 
487
        let (h2,l2) = decompose_app t2 in
 
488
        if List.length l1 = List.length l2 then
 
489
          f h1 h2 & List.for_all2 f l1 l2
 
490
        else false
 
491
  | Evar (e1,l1), Evar (e2,l2) -> e1 = e2 & array_for_all2 f l1 l2
 
492
  | Const c1, Const c2 -> c1 = c2
 
493
  | Ind c1, Ind c2 -> c1 = c2
 
494
  | Construct c1, Construct c2 -> c1 = c2
 
495
  | Case (_,p1,c1,bl1), Case (_,p2,c2,bl2) ->
 
496
      f p1 p2 & f c1 c2 & array_for_all2 f bl1 bl2
 
497
  | Fix (ln1,(_,tl1,bl1)), Fix (ln2,(_,tl2,bl2)) ->
 
498
      ln1 = ln2 & array_for_all2 f tl1 tl2 & array_for_all2 f bl1 bl2
 
499
  | CoFix(ln1,(_,tl1,bl1)), CoFix(ln2,(_,tl2,bl2)) ->
 
500
      ln1 = ln2 & array_for_all2 f tl1 tl2 & array_for_all2 f bl1 bl2
 
501
  | _ -> false
 
502
 
 
503
let rec eq_constr m n = 
 
504
  (m==n) or
 
505
  compare_constr eq_constr m n
 
506
 
 
507
let eq_constr m n = eq_constr m n (* to avoid tracing a recursive fun *)