]> matita.cs.unibo.it Git - helm.git/blob - helm/gTopLevel/proofEngineReduction.ml
* Bug fixed: syntactic equality for CIC term (which was used in the Fold tactic)
[helm.git] / helm / gTopLevel / proofEngineReduction.ml
1 (* Copyright (C) 2000, HELM Team.
2  * 
3  * This file is part of HELM, an Hypertextual, Electronic
4  * Library of Mathematics, developed at the Computer Science
5  * Department, University of Bologna, Italy.
6  * 
7  * HELM is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * 
12  * HELM is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with HELM; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20  * MA  02111-1307, USA.
21  * 
22  * For details, see the HELM World-Wide-Web page,
23  * http://cs.unibo.it/helm/.
24  *)
25
26 (******************************************************************************)
27 (*                                                                            *)
28 (*                               PROJECT HELM                                 *)
29 (*                                                                            *)
30 (*                Claudio Sacerdoti Coen <sacerdot@cs.unibo.it>               *)
31 (*                                 12/04/2002                                 *)
32 (*                                                                            *)
33 (*                                                                            *)
34 (******************************************************************************)
35
36
37 (* The code of this module is derived from the code of CicReduction *)
38
39 exception Impossible of int;;
40 exception ReferenceToDefinition;;
41 exception ReferenceToAxiom;;
42 exception ReferenceToVariable;;
43 exception ReferenceToCurrentProof;;
44 exception ReferenceToInductiveDefinition;;
45 exception WrongUriToInductiveDefinition;;
46 exception RelToHiddenHypothesis;;
47
48 (* syntactic_equality up to cookingsno for uris *)
49 (* (which is often syntactically irrilevant)    *)
50 let rec syntactic_equality t t' =
51  let module C = Cic in
52   if t = t' then true
53   else
54    match t,t' with
55       C.Rel _, C.Rel _
56     | C.Var _, C.Var _
57     | C.Meta _, C.Meta _
58     | C.Sort _, C.Sort _
59     | C.Implicit, C.Implicit -> false (* we already know that t != t' *)
60     | C.Cast (te,ty), C.Cast (te',ty') ->
61        syntactic_equality te te' &&
62         syntactic_equality ty ty'
63     | C.Prod (n,s,t), C.Prod (n',s',t') ->
64        n = n' &&
65         syntactic_equality s s' &&
66          syntactic_equality t t'
67     | C.Lambda (n,s,t), C.Lambda (n',s',t') ->
68        n = n' &&
69         syntactic_equality s s' &&
70          syntactic_equality t t'
71     | C.LetIn (n,s,t), C.LetIn(n',s',t') ->
72        n = n' &&
73         syntactic_equality s s' &&
74          syntactic_equality t t'
75     | C.Appl l, C.Appl l' ->
76        List.fold_left2 (fun b t1 t2 -> b && syntactic_equality t1 t2) true l l'
77     | C.Const (uri,_), C.Const (uri',_) -> UriManager.eq uri uri'
78     | C.Abst _, C.Abst _ -> assert false
79     | C.MutInd (uri,_,i), C.MutInd (uri',_,i') ->
80        UriManager.eq uri uri' && i = i'
81     | C.MutConstruct (uri,_,i,j), C.MutConstruct (uri',_,i',j') ->
82        UriManager.eq uri uri' && i = i' && j = j'
83     | C.MutCase (sp,_,i,outt,t,pl), C.MutCase (sp',_,i',outt',t',pl') ->
84        UriManager.eq sp sp' && i = i' &&
85         syntactic_equality outt outt' &&
86          syntactic_equality t t' &&
87           List.fold_left2
88            (fun b t1 t2 -> b && syntactic_equality t1 t2) true pl pl'
89     | C.Fix (i,fl), C.Fix (i',fl') ->
90        i = i' &&
91         List.fold_left2
92          (fun b (name,i,ty,bo) (name',i',ty',bo') ->
93            b && name = name' && i = i' &&
94             syntactic_equality ty ty' &&
95              syntactic_equality bo bo') true fl fl'
96     | C.CoFix (i,fl), C.CoFix (i',fl') ->
97        i = i' &&
98         List.fold_left2
99          (fun b (name,ty,bo) (name',ty',bo') ->
100            b && name = name' &&
101             syntactic_equality ty ty' &&
102              syntactic_equality bo bo') true fl fl'
103     | _,_ -> false
104 ;;
105
106 (* "textual" replacement of a subterm with another one *)
107 let replace ~equality ~what ~with_what ~where =
108  let module C = Cic in
109   let rec aux =
110    function
111       t when (equality t what) -> with_what
112     | C.Rel _ as t -> t
113     | C.Var _ as t  -> t
114     | C.Meta _ as t -> t
115     | C.Sort _ as t -> t
116     | C.Implicit as t -> t
117     | C.Cast (te,ty) -> C.Cast (aux te, aux ty)
118     | C.Prod (n,s,t) -> C.Prod (n, aux s, aux t)
119     | C.Lambda (n,s,t) -> C.Lambda (n, aux s, aux t)
120     | C.LetIn (n,s,t) -> C.LetIn (n, aux s, aux t)
121     | C.Appl l ->
122        (* Invariant enforced: no application of an application *)
123        (match List.map aux l with
124            (C.Appl l')::tl -> C.Appl (l'@tl)
125          | l' -> C.Appl l')
126     | C.Const _ as t -> t
127     | C.Abst _ as t -> t
128     | C.MutInd _ as t -> t
129     | C.MutConstruct _ as t -> t
130     | C.MutCase (sp,cookingsno,i,outt,t,pl) ->
131        C.MutCase (sp,cookingsno,i,aux outt, aux t,
132         List.map aux pl)
133     | C.Fix (i,fl) ->
134        let substitutedfl =
135         List.map
136          (fun (name,i,ty,bo) -> (name, i, aux ty, aux bo))
137           fl
138        in
139         C.Fix (i, substitutedfl)
140     | C.CoFix (i,fl) ->
141        let substitutedfl =
142         List.map
143          (fun (name,ty,bo) -> (name, aux ty, aux bo))
144           fl
145        in
146         C.CoFix (i, substitutedfl)
147   in
148    aux where
149 ;;
150
151 (* Takes a well-typed term and fully reduces it. *)
152 (*CSC: It does not perform reduction in a Case *)
153 let reduce context =
154  let rec reduceaux context l =
155   let module C = Cic in
156   let module S = CicSubstitution in
157    function
158       C.Rel n as t ->
159        (match List.nth context (n-1) with
160            Some (_,C.Decl _) -> if l = [] then t else C.Appl (t::l)
161          | Some (_,C.Def bo) -> reduceaux context l (S.lift n bo)
162          | None -> raise RelToHiddenHypothesis
163        )
164     | C.Var uri as t ->
165        (match CicEnvironment.get_cooked_obj uri 0 with
166            C.Definition _ -> raise ReferenceToDefinition
167          | C.Axiom _ -> raise ReferenceToAxiom
168          | C.CurrentProof _ -> raise ReferenceToCurrentProof
169          | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
170          | C.Variable (_,None,_) -> if l = [] then t else C.Appl (t::l)
171          | C.Variable (_,Some body,_) -> reduceaux context l body
172        )
173     | C.Meta _ as t -> if l = [] then t else C.Appl (t::l)
174     | C.Sort _ as t -> t (* l should be empty *)
175     | C.Implicit as t -> t
176     | C.Cast (te,ty) ->
177        C.Cast (reduceaux context l te, reduceaux context l ty)
178     | C.Prod (name,s,t) ->
179        assert (l = []) ;
180        C.Prod (name,
181         reduceaux context [] s,
182         reduceaux ((Some (name,C.Decl s))::context) [] t)
183     | C.Lambda (name,s,t) ->
184        (match l with
185            [] ->
186             C.Lambda (name,
187              reduceaux context [] s,
188              reduceaux ((Some (name,C.Decl s))::context) [] t)
189          | he::tl -> reduceaux context tl (S.subst he t)
190            (* when name is Anonimous the substitution should be superfluous *)
191        )
192     | C.LetIn (n,s,t) ->
193        reduceaux context l (S.subst (reduceaux context [] s) t)
194     | C.Appl (he::tl) ->
195        let tl' = List.map (reduceaux context []) tl in
196         reduceaux context (tl'@l) he
197     | C.Appl [] -> raise (Impossible 1)
198     | C.Const (uri,cookingsno) as t ->
199        (match CicEnvironment.get_cooked_obj uri cookingsno with
200            C.Definition (_,body,_,_) -> reduceaux context l body
201          | C.Axiom _ -> if l = [] then t else C.Appl (t::l)
202          | C.Variable _ -> raise ReferenceToVariable
203          | C.CurrentProof (_,_,body,_) -> reduceaux context l body
204          | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
205        )
206     | C.Abst _ as t -> t (*CSC l should be empty ????? *)
207     | C.MutInd (uri,_,_) as t -> if l = [] then t else C.Appl (t::l)
208     | C.MutConstruct (uri,_,_,_) as t -> if l = [] then t else C.Appl (t::l)
209     | C.MutCase (mutind,cookingsno,i,outtype,term,pl) ->
210        let decofix =
211         function
212            C.CoFix (i,fl) as t ->
213             let tys =
214              List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl
215             in
216              let (_,_,body) = List.nth fl i in
217               let body' =
218                let counter = ref (List.length fl) in
219                 List.fold_right
220                  (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
221                  fl
222                  body
223               in
224                reduceaux (tys@context) [] body'
225          | C.Appl (C.CoFix (i,fl) :: tl) ->
226             let tys =
227              List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl
228             in
229              let (_,_,body) = List.nth fl i in
230               let body' =
231                let counter = ref (List.length fl) in
232                 List.fold_right
233                  (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
234                  fl
235                  body
236               in
237                let tl' = List.map (reduceaux context []) tl in
238                 reduceaux (tys@context) tl' body'
239          | t -> t
240        in
241         (match decofix (reduceaux context [] term) with
242             C.MutConstruct (_,_,_,j) -> reduceaux context l (List.nth pl (j-1))
243           | C.Appl (C.MutConstruct (_,_,_,j) :: tl) ->
244              let (arity, r, num_ingredients) =
245               match CicEnvironment.get_obj mutind with
246                  C.InductiveDefinition (tl,ingredients,r) ->
247                    let (_,_,arity,_) = List.nth tl i
248                    and num_ingredients =
249                     List.fold_right
250                      (fun (k,l) i ->
251                        if k < cookingsno then i + List.length l else i
252                      ) ingredients 0
253                    in
254                     (arity,r,num_ingredients)
255                | _ -> raise WrongUriToInductiveDefinition
256              in
257               let ts =
258                let num_to_eat = r + num_ingredients in
259                 let rec eat_first =
260                  function
261                     (0,l) -> l
262                   | (n,he::tl) when n > 0 -> eat_first (n - 1, tl)
263                   | _ -> raise (Impossible 5)
264                 in
265                  eat_first (num_to_eat,tl)
266               in
267                reduceaux context (ts@l) (List.nth pl (j-1))
268          | C.Abst _ | C.Cast _ | C.Implicit ->
269             raise (Impossible 2) (* we don't trust our whd ;-) *)
270          | _ ->
271            let outtype' = reduceaux context [] outtype in
272            let term' = reduceaux context [] term in
273            let pl' = List.map (reduceaux context []) pl in
274             let res =
275              C.MutCase (mutind,cookingsno,i,outtype',term',pl')
276             in
277              if l = [] then res else C.Appl (res::l)
278        )
279     | C.Fix (i,fl) ->
280        let tys =
281         List.map (function (name,_,ty,_) -> Some (C.Name name, C.Decl ty)) fl
282        in
283         let t' () =
284          let fl' =
285           List.map
286            (function (n,recindex,ty,bo) ->
287              (n,recindex,reduceaux context [] ty, reduceaux (tys@context) [] bo)
288            ) fl
289          in
290           C.Fix (i, fl')
291         in
292          let (_,recindex,_,body) = List.nth fl i in
293           let recparam =
294            try
295             Some (List.nth l recindex)
296            with
297             _ -> None
298           in
299            (match recparam with
300                Some recparam ->
301                 (match reduceaux context [] recparam with
302                     C.MutConstruct _
303                   | C.Appl ((C.MutConstruct _)::_) ->
304                      let body' =
305                       let counter = ref (List.length fl) in
306                        List.fold_right
307                         (fun _ -> decr counter ; S.subst (C.Fix (!counter,fl)))
308                         fl
309                         body
310                      in
311                       (* Possible optimization: substituting whd recparam in l*)
312                       reduceaux context l body'
313                   | _ -> if l = [] then t' () else C.Appl ((t' ())::l)
314                 )
315              | None -> if l = [] then t' () else C.Appl ((t' ())::l)
316            )
317     | C.CoFix (i,fl) ->
318        let tys =
319         List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl
320        in
321         let t' =
322          let fl' =
323           List.map
324            (function (n,ty,bo) ->
325              (n,reduceaux context [] ty, reduceaux (tys@context) [] bo)
326            ) fl
327          in
328           C.CoFix (i, fl')
329         in
330          if l = [] then t' else C.Appl (t'::l)
331  in
332   reduceaux context []
333 ;;
334
335 exception WrongShape;;
336 exception AlreadySimplified;;
337 exception WhatShouldIDo;;
338
339 (*CSC: I fear it is still weaker than Coq's one. For example, Coq is *)
340 (*CSCS: able to simpl (foo (S n) (S n)) to (foo (S O) n) where       *)
341 (*CSC:  Fix foo                                                      *)
342 (*CSC:   {foo [n,m:nat]:nat :=                                       *)
343 (*CSC:     Cases m of O => n | (S p) => (foo (S O) p) end            *)
344 (*CSC:   }                                                           *)
345 (* Takes a well-typed term and                                               *)
346 (*  1) Performs beta-iota-zeta reduction until delta reduction is needed     *)
347 (*  2) Attempts delta-reduction. If the residual is a Fix lambda-abstracted  *)
348 (*     w.r.t. zero or more variables and if the Fix can be reduced, than it  *)
349 (*     is reduced, the delta-reduction is succesfull and the whole algorithm *)
350 (*     is applied again to the new redex; Step 3) is applied to the result   *)
351 (*     of the recursive simplification. Otherwise, if the Fix can not be     *)
352 (*     reduced, than the delta-reductions fails and the delta-redex is       *)
353 (*     not reduced. Otherwise, if the delta-residual is not the              *)
354 (*     lambda-abstraction of a Fix, then it is reduced and the result is     *)
355 (*     directly returned, without performing step 3).                        *) 
356 (*  3) Folds the application of the constant to the arguments that did not   *)
357 (*     change in every iteration, i.e. to the actual arguments for the       *)
358 (*     lambda-abstractions that precede the Fix.                             *)
359 (*CSC: It does not perform simplification in a Case *)
360 let simpl context =
361  (* reduceaux is equal to the reduceaux locally defined inside *)
362  (*reduce, but for the const case.                             *) 
363  (**** Step 1 ****)
364  let rec reduceaux context l =
365   let module C = Cic in
366   let module S = CicSubstitution in
367    function
368       C.Rel n as t ->
369        (match List.nth context (n-1) with
370            Some (_,C.Decl _) -> if l = [] then t else C.Appl (t::l)
371          | Some (_,C.Def bo) -> reduceaux context l (S.lift n bo)
372          | None -> raise RelToHiddenHypothesis
373        )
374     | C.Var uri as t ->
375        (match CicEnvironment.get_cooked_obj uri 0 with
376            C.Definition _ -> raise ReferenceToDefinition
377          | C.Axiom _ -> raise ReferenceToAxiom
378          | C.CurrentProof _ -> raise ReferenceToCurrentProof
379          | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
380          | C.Variable (_,None,_) -> if l = [] then t else C.Appl (t::l)
381          | C.Variable (_,Some body,_) -> reduceaux context l body
382        )
383     | C.Meta _ as t -> if l = [] then t else C.Appl (t::l)
384     | C.Sort _ as t -> t (* l should be empty *)
385     | C.Implicit as t -> t
386     | C.Cast (te,ty) ->
387        C.Cast (reduceaux context l te, reduceaux context l ty)
388     | C.Prod (name,s,t) ->
389        assert (l = []) ;
390        C.Prod (name,
391         reduceaux context [] s,
392         reduceaux ((Some (name,C.Decl s))::context) [] t)
393     | C.Lambda (name,s,t) ->
394        (match l with
395            [] ->
396             C.Lambda (name,
397              reduceaux context [] s,
398              reduceaux ((Some (name,C.Decl s))::context) [] t)
399          | he::tl -> reduceaux context tl (S.subst he t)
400            (* when name is Anonimous the substitution should be superfluous *)
401        )
402     | C.LetIn (n,s,t) ->
403        reduceaux context l (S.subst (reduceaux context [] s) t)
404     | C.Appl (he::tl) ->
405        let tl' = List.map (reduceaux context []) tl in
406         reduceaux context (tl'@l) he
407     | C.Appl [] -> raise (Impossible 1)
408     | C.Const (uri,cookingsno) as t ->
409        (match CicEnvironment.get_cooked_obj uri cookingsno with
410            C.Definition (_,body,_,_) ->
411             begin
412              try
413               (**** Step 2 ****)
414               let res,constant_args =
415                let rec aux rev_constant_args l =
416                 function
417                    C.Lambda (name,s,t) as t' ->
418                     begin
419                      match l with
420                         [] -> raise WrongShape
421                       | he::tl ->
422                          (* when name is Anonimous the substitution should be *)
423                          (* superfluous                                       *)
424                          aux (he::rev_constant_args) tl (S.subst he t)
425                     end
426                  | C.LetIn (_,_,_) -> raise WhatShouldIDo (*CSC: ?????????? *)
427                  | C.Fix (i,fl) as t ->
428                     let tys =
429                      List.map (function (name,_,ty,_) ->
430                       Some (C.Name name, C.Decl ty)) fl
431                     in
432                      let (_,recindex,_,body) = List.nth fl i in
433                       let recparam =
434                        try
435                         List.nth l recindex
436                        with
437                         _ -> raise AlreadySimplified
438                       in
439                        (match CicReduction.whd context recparam with
440                            C.MutConstruct _
441                          | C.Appl ((C.MutConstruct _)::_) ->
442                             let body' =
443                              let counter = ref (List.length fl) in
444                               List.fold_right
445                                (function _ ->
446                                  decr counter ; S.subst (C.Fix (!counter,fl))
447                                ) fl body
448                             in
449                              (* Possible optimization: substituting whd *)
450                              (* recparam in l                           *)
451                              reduceaux (tys@context) l body',
452                               List.rev rev_constant_args
453                          | _ -> raise AlreadySimplified
454                        )
455                  | _ -> raise WrongShape
456                in
457                 aux [] l body
458               in
459                (**** Step 3 ****)
460                let term_to_fold =
461                 match constant_args with
462                    [] -> C.Const (uri,cookingsno)
463                  | _ -> C.Appl ((C.Const (uri,cookingsno))::constant_args)
464                in
465                 let reduced_term_to_fold = reduce context term_to_fold in
466                  replace (=) reduced_term_to_fold term_to_fold res
467              with
468                 WrongShape ->
469                  (* The constant does not unfold to a Fix lambda-abstracted   *)
470                  (* w.r.t. zero or more variables. We just perform reduction. *)
471                  reduceaux context l body
472               | AlreadySimplified ->
473                  (* If we performed delta-reduction, we would find a Fix   *)
474                  (* not applied to a constructor. So, we refuse to perform *)
475                  (* delta-reduction.                                       *)
476                  if l = [] then
477                     t
478                  else
479                   C.Appl (t::l)
480             end
481          | C.Axiom _ -> if l = [] then t else C.Appl (t::l)
482          | C.Variable _ -> raise ReferenceToVariable
483          | C.CurrentProof (_,_,body,_) -> reduceaux context l body
484          | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
485        )
486     | C.Abst _ as t -> t (*CSC l should be empty ????? *)
487     | C.MutInd (uri,_,_) as t -> if l = [] then t else C.Appl (t::l)
488     | C.MutConstruct (uri,_,_,_) as t -> if l = [] then t else C.Appl (t::l)
489     | C.MutCase (mutind,cookingsno,i,outtype,term,pl) ->
490        let decofix =
491         function
492            C.CoFix (i,fl) as t ->
493             let tys =
494              List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl            in
495              let (_,_,body) = List.nth fl i in
496               let body' =
497                let counter = ref (List.length fl) in
498                 List.fold_right
499                  (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
500                  fl
501                  body
502               in
503                reduceaux (tys@context) [] body'
504          | C.Appl (C.CoFix (i,fl) :: tl) ->
505             let tys =
506              List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl            in
507              let (_,_,body) = List.nth fl i in
508               let body' =
509                let counter = ref (List.length fl) in
510                 List.fold_right
511                  (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
512                  fl
513                  body
514               in
515                let tl' = List.map (reduceaux context []) tl in
516                 reduceaux (tys@context) tl body'
517          | t -> t
518        in
519         (match decofix (reduceaux context [] term) with
520             C.MutConstruct (_,_,_,j) -> reduceaux context l (List.nth pl (j-1))
521           | C.Appl (C.MutConstruct (_,_,_,j) :: tl) ->
522              let (arity, r, num_ingredients) =
523               match CicEnvironment.get_obj mutind with
524                  C.InductiveDefinition (tl,ingredients,r) ->
525                    let (_,_,arity,_) = List.nth tl i
526                    and num_ingredients =
527                     List.fold_right
528                      (fun (k,l) i ->
529                        if k < cookingsno then i + List.length l else i
530                      ) ingredients 0
531                    in
532                     (arity,r,num_ingredients)
533                | _ -> raise WrongUriToInductiveDefinition
534              in
535               let ts =
536                let num_to_eat = r + num_ingredients in
537                 let rec eat_first =
538                  function
539                     (0,l) -> l
540                   | (n,he::tl) when n > 0 -> eat_first (n - 1, tl)
541                   | _ -> raise (Impossible 5)
542                 in
543                  eat_first (num_to_eat,tl)
544               in
545                reduceaux context (ts@l) (List.nth pl (j-1))
546          | C.Abst _ | C.Cast _ | C.Implicit ->
547             raise (Impossible 2) (* we don't trust our whd ;-) *)
548          | _ ->
549            let outtype' = reduceaux context [] outtype in
550            let term' = reduceaux context [] term in
551            let pl' = List.map (reduceaux context []) pl in
552             let res =
553              C.MutCase (mutind,cookingsno,i,outtype',term',pl')
554             in
555              if l = [] then res else C.Appl (res::l)
556        )
557     | C.Fix (i,fl) ->
558        let tys =
559         List.map (function (name,_,ty,_) -> Some (C.Name name, C.Decl ty)) fl
560        in
561         let t' () =
562          let fl' =
563           List.map
564            (function (n,recindex,ty,bo) ->
565              (n,recindex,reduceaux context [] ty, reduceaux (tys@context) [] bo)
566            ) fl
567          in
568           C.Fix (i, fl')
569         in
570          let (_,recindex,_,body) = List.nth fl i in
571           let recparam =
572            try
573             Some (List.nth l recindex)
574            with
575             _ -> None
576           in
577            (match recparam with
578                Some recparam ->
579                 (match reduceaux context [] recparam with
580                     C.MutConstruct _
581                   | C.Appl ((C.MutConstruct _)::_) ->
582                      let body' =
583                       let counter = ref (List.length fl) in
584                        List.fold_right
585                         (fun _ -> decr counter ; S.subst (C.Fix (!counter,fl)))
586                         fl
587                         body
588                      in
589                       (* Possible optimization: substituting whd recparam in l*)
590                       reduceaux context l body'
591                   | _ -> if l = [] then t' () else C.Appl ((t' ())::l)
592                 )
593              | None -> if l = [] then t' () else C.Appl ((t' ())::l)
594            )
595     | C.CoFix (i,fl) ->
596        let tys =
597         List.map (function (name,ty,_) -> Some (C.Name name, C.Decl ty)) fl
598        in
599         let t' =
600          let fl' =
601           List.map
602            (function (n,ty,bo) ->
603              (n,reduceaux context [] ty, reduceaux (tys@context) [] bo)
604            ) fl
605          in
606          C.CoFix (i, fl')
607        in
608          if l = [] then t' else C.Appl (t'::l)
609  in
610   reduceaux context []
611 ;;