1 (* Copyright (C) 2000, HELM Team.
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.
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.
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.
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,
22 * For details, see the HELM World-Wide-Web page,
23 * http://cs.unibo.it/helm/.
26 (******************************************************************************)
30 (* Claudio Sacerdoti Coen <sacerdot@cs.unibo.it> *)
34 (******************************************************************************)
37 (* The code of this module is derived from the code of CicReduction *)
39 exception Impossible of int;;
40 exception ReferenceToDefinition;;
41 exception ReferenceToAxiom;;
42 exception ReferenceToVariable;;
43 exception ReferenceToCurrentProof;;
44 exception ReferenceToInductiveDefinition;;
45 exception WrongUriToInductiveDefinition;;
47 (* "textual" replacement of a subterm with another one *)
48 let replace ~what ~with_what ~where =
52 t when t = what -> with_what
57 | C.Implicit as t -> t
58 | C.Cast (te,ty) -> C.Cast (aux te, aux ty)
59 | C.Prod (n,s,t) -> C.Prod (n, aux s, aux t)
60 | C.Lambda (n,s,t) -> C.Lambda (n, aux s, aux t)
61 | C.LetIn (n,s,t) -> C.LetIn (n, aux s, aux t)
62 | C.Appl l -> C.Appl (List.map aux l)
65 | C.MutInd _ as t -> t
66 | C.MutConstruct _ as t -> t
67 | C.MutCase (sp,cookingsno,i,outt,t,pl) ->
68 C.MutCase (sp,cookingsno,i,aux outt, aux t,
73 (fun (name,i,ty,bo) -> (name, i, aux ty, aux bo))
76 C.Fix (i, substitutedfl)
80 (fun (name,ty,bo) -> (name, aux ty, aux bo))
83 C.CoFix (i, substitutedfl)
88 (* Takes a well-typed term and fully reduces it. *)
89 (*CSC: It does not perform reduction in a Case *)
93 let module S = CicSubstitution in
95 C.Rel _ as t -> if l = [] then t else C.Appl (t::l)
97 (match CicEnvironment.get_cooked_obj uri 0 with
98 C.Definition _ -> raise ReferenceToDefinition
99 | C.Axiom _ -> raise ReferenceToAxiom
100 | C.CurrentProof _ -> raise ReferenceToCurrentProof
101 | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
102 | C.Variable (_,None,_) -> if l = [] then t else C.Appl (t::l)
103 | C.Variable (_,Some body,_) -> reduceaux l body
105 | C.Meta _ as t -> if l = [] then t else C.Appl (t::l)
106 | C.Sort _ as t -> t (* l should be empty *)
107 | C.Implicit as t -> t
108 | C.Cast (te,ty) -> reduceaux l te (*CSC E' GIUSTO BUTTARE IL CAST? *)
109 | C.Prod (name,s,t) ->
111 C.Prod (name, reduceaux [] s, reduceaux [] t)
112 | C.Lambda (name,s,t) ->
114 [] -> C.Lambda (name, reduceaux [] s, reduceaux [] t)
115 | he::tl -> reduceaux tl (S.subst he t)
116 (* when name is Anonimous the substitution should be superfluous *)
118 | C.LetIn (n,s,t) -> reduceaux l (S.subst (reduceaux [] s) t)
120 let tl' = List.map (reduceaux []) tl in
122 | C.Appl [] -> raise (Impossible 1)
123 | C.Const (uri,cookingsno) as t ->
124 (match CicEnvironment.get_cooked_obj uri cookingsno with
125 C.Definition (_,body,_,_) -> reduceaux l body
126 | C.Axiom _ -> if l = [] then t else C.Appl (t::l)
127 | C.Variable _ -> raise ReferenceToVariable
128 | C.CurrentProof (_,_,body,_) -> reduceaux l body
129 | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
131 | C.Abst _ as t -> t (*CSC l should be empty ????? *)
132 | C.MutInd (uri,_,_) as t -> if l = [] then t else C.Appl (t::l)
133 | C.MutConstruct (uri,_,_,_) as t -> if l = [] then t else C.Appl (t::l)
134 | C.MutCase (mutind,cookingsno,i,outtype,term,pl) ->
137 C.CoFix (i,fl) as t ->
138 let (_,_,body) = List.nth fl i in
140 let counter = ref (List.length fl) in
142 (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
147 | C.Appl (C.CoFix (i,fl) :: tl) ->
148 let (_,_,body) = List.nth fl i in
150 let counter = ref (List.length fl) in
152 (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
156 let tl' = List.map (reduceaux []) tl in
160 (match decofix (reduceaux [] term) with
161 C.MutConstruct (_,_,_,j) -> reduceaux l (List.nth pl (j-1))
162 | C.Appl (C.MutConstruct (_,_,_,j) :: tl) ->
163 let (arity, r, num_ingredients) =
164 match CicEnvironment.get_obj mutind with
165 C.InductiveDefinition (tl,ingredients,r) ->
166 let (_,_,arity,_) = List.nth tl i
167 and num_ingredients =
170 if k < cookingsno then i + List.length l else i
173 (arity,r,num_ingredients)
174 | _ -> raise WrongUriToInductiveDefinition
177 let num_to_eat = r + num_ingredients in
181 | (n,he::tl) when n > 0 -> eat_first (n - 1, tl)
182 | _ -> raise (Impossible 5)
184 eat_first (num_to_eat,tl)
186 reduceaux (ts@l) (List.nth pl (j-1))
187 | C.Abst _ | C.Cast _ | C.Implicit ->
188 raise (Impossible 2) (* we don't trust our whd ;-) *)
190 let outtype' = reduceaux [] outtype in
191 let term' = reduceaux [] term in
192 let pl' = List.map (reduceaux []) pl in
194 C.MutCase (mutind,cookingsno,i,outtype',term',pl')
196 if l = [] then res else C.Appl (res::l)
202 (function (n,recindex,ty,bo) ->
203 (n,recindex,reduceaux [] ty, reduceaux [] bo)
208 let (_,recindex,_,body) = List.nth fl i in
211 Some (List.nth l recindex)
217 (match reduceaux [] recparam with
219 | C.Appl ((C.MutConstruct _)::_) ->
221 let counter = ref (List.length fl) in
223 (fun _ -> decr counter ; S.subst (C.Fix (!counter,fl)))
227 (* Possible optimization: substituting whd recparam in l *)
229 | _ -> if l = [] then t' () else C.Appl ((t' ())::l)
231 | None -> if l = [] then t' () else C.Appl ((t' ())::l)
237 (function (n,ty,bo) ->
238 (n,reduceaux [] ty, reduceaux [] bo)
243 if l = [] then t' else C.Appl (t'::l)
245 function t -> let res =
246 prerr_endline ("<<<<<<<<<<<<<<<<" ^ CicPp.ppterm t) ; flush stderr ;
248 t in prerr_endline ("++++++++++++++++++" ^ CicPp.ppterm res) ; flush stderr ; res
251 exception WrongShape;;
252 exception AlreadySimplified;;
253 exception WhatShouldIDo;;
255 (*CSC: I fear it is still weaker than Coq's one. For example, Coq is *)
256 (*CSCS: able to simpl (foo (S n) (S n)) to (foo (S O) n) where *)
258 (*CSC: {foo [n,m:nat]:nat := *)
259 (*CSC: Cases m of O => n | (S p) => (foo (S O) p) end *)
261 (* Takes a well-typed term and *)
262 (* 1) Performs beta-iota-zeta reduction until delta reduction is needed *)
263 (* 2) Attempts delta-reduction. If the residual is a Fix lambda-abstracted *)
264 (* w.r.t. zero or more variables and if the Fix can be reduced, than it *)
265 (* is reduced, the delta-reduction is succesfull and the whole algorithm *)
266 (* is applied again to the new redex; Step 3) is applied to the result *)
267 (* of the recursive simplification. Otherwise, if the Fix can not be *)
268 (* reduced, than the delta-reductions fails and the delta-redex is *)
269 (* not reduced. Otherwise, if the delta-residual is not the *)
270 (* lambda-abstraction of a Fix, then it is reduced and the result is *)
271 (* directly returned, without performing step 3). *)
272 (* 3) Folds the application of the constant to the arguments that did not *)
273 (* change in every iteration, i.e. to the actual arguments for the *)
274 (* lambda-abstractions that precede the Fix. *)
275 (*CSC: It does not perform simplification in a Case *)
277 (* reduceaux is equal to the reduceaux locally defined inside *)
278 (*reduce, but for the const case. *)
280 let rec reduceaux l =
281 let module C = Cic in
282 let module S = CicSubstitution in
284 C.Rel _ as t -> if l = [] then t else C.Appl (t::l)
286 (match CicEnvironment.get_cooked_obj uri 0 with
287 C.Definition _ -> raise ReferenceToDefinition
288 | C.Axiom _ -> raise ReferenceToAxiom
289 | C.CurrentProof _ -> raise ReferenceToCurrentProof
290 | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
291 | C.Variable (_,None,_) -> if l = [] then t else C.Appl (t::l)
292 | C.Variable (_,Some body,_) -> reduceaux l body
294 | C.Meta _ as t -> if l = [] then t else C.Appl (t::l)
295 | C.Sort _ as t -> t (* l should be empty *)
296 | C.Implicit as t -> t
297 | C.Cast (te,ty) -> reduceaux l te (*CSC E' GIUSTO BUTTARE IL CAST? *)
298 | C.Prod (name,s,t) ->
300 C.Prod (name, reduceaux [] s, reduceaux [] t)
301 | C.Lambda (name,s,t) ->
303 [] -> C.Lambda (name, reduceaux [] s, reduceaux [] t)
304 | he::tl -> reduceaux tl (S.subst he t)
305 (* when name is Anonimous the substitution should be superfluous *)
307 | C.LetIn (n,s,t) -> reduceaux l (S.subst (reduceaux [] s) t)
309 let tl' = List.map (reduceaux []) tl in
311 | C.Appl [] -> raise (Impossible 1)
312 | C.Const (uri,cookingsno) as t ->
313 (match CicEnvironment.get_cooked_obj uri cookingsno with
314 C.Definition (_,body,_,_) ->
318 let res,constant_args =
319 let rec aux rev_constant_args l =
321 C.Lambda (name,s,t) as t' ->
324 [] -> raise WrongShape
326 (* when name is Anonimous the substitution should be *)
328 aux (he::rev_constant_args) tl (S.subst he t)
330 | C.LetIn (_,_,_) -> raise WhatShouldIDo (*CSC: ?????????? *)
331 | C.Fix (i,fl) as t ->
332 let (_,recindex,_,body) = List.nth fl i in
337 _ -> raise AlreadySimplified
339 (match CicReduction.whd recparam with
341 | C.Appl ((C.MutConstruct _)::_) ->
343 let counter = ref (List.length fl) in
346 decr counter ; S.subst (C.Fix (!counter,fl))
349 (* Possible optimization: substituting whd *)
351 reduceaux l body', List.rev rev_constant_args
352 | _ -> raise AlreadySimplified
354 | _ -> raise WrongShape
360 match constant_args with
361 [] -> C.Const (uri,cookingsno)
362 | _ -> C.Appl ((C.Const (uri,cookingsno))::constant_args)
364 let reduced_term_to_fold = reduce term_to_fold in
365 prerr_endline ("TERM TO FOLD: " ^ CicPp.ppterm term_to_fold) ; flush stderr ;
366 prerr_endline ("REDUCED TERM TO FOLD: " ^ CicPp.ppterm reduced_term_to_fold) ; flush stderr ;
367 replace reduced_term_to_fold term_to_fold res
370 (* The constant does not unfold to a Fix lambda-abstracted *)
371 (* w.r.t. zero or more variables. We just perform reduction. *)
373 | AlreadySimplified ->
374 (* If we performed delta-reduction, we would find a Fix *)
375 (* not applied to a constructor. So, we refuse to perform *)
376 (* delta-reduction. *)
382 | C.Axiom _ -> if l = [] then t else C.Appl (t::l)
383 | C.Variable _ -> raise ReferenceToVariable
384 | C.CurrentProof (_,_,body,_) -> reduceaux l body
385 | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
387 | C.Abst _ as t -> t (*CSC l should be empty ????? *)
388 | C.MutInd (uri,_,_) as t -> if l = [] then t else C.Appl (t::l)
389 | C.MutConstruct (uri,_,_,_) as t -> if l = [] then t else C.Appl (t::l)
390 | C.MutCase (mutind,cookingsno,i,outtype,term,pl) ->
393 C.CoFix (i,fl) as t ->
394 let (_,_,body) = List.nth fl i in
396 let counter = ref (List.length fl) in
398 (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
403 | C.Appl (C.CoFix (i,fl) :: tl) ->
404 let (_,_,body) = List.nth fl i in
406 let counter = ref (List.length fl) in
408 (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
412 let tl' = List.map (reduceaux []) tl in
416 (match decofix (reduceaux [] term) with
417 C.MutConstruct (_,_,_,j) -> reduceaux l (List.nth pl (j-1))
418 | C.Appl (C.MutConstruct (_,_,_,j) :: tl) ->
419 let (arity, r, num_ingredients) =
420 match CicEnvironment.get_obj mutind with
421 C.InductiveDefinition (tl,ingredients,r) ->
422 let (_,_,arity,_) = List.nth tl i
423 and num_ingredients =
426 if k < cookingsno then i + List.length l else i
429 (arity,r,num_ingredients)
430 | _ -> raise WrongUriToInductiveDefinition
433 let num_to_eat = r + num_ingredients in
437 | (n,he::tl) when n > 0 -> eat_first (n - 1, tl)
438 | _ -> raise (Impossible 5)
440 eat_first (num_to_eat,tl)
442 reduceaux (ts@l) (List.nth pl (j-1))
443 | C.Abst _ | C.Cast _ | C.Implicit ->
444 raise (Impossible 2) (* we don't trust our whd ;-) *)
446 let outtype' = reduceaux [] outtype in
447 let term' = reduceaux [] term in
448 let pl' = List.map (reduceaux []) pl in
450 C.MutCase (mutind,cookingsno,i,outtype',term',pl')
452 if l = [] then res else C.Appl (res::l)
458 (function (n,recindex,ty,bo) ->
459 (n,recindex,reduceaux [] ty, reduceaux [] bo)
464 let (_,recindex,_,body) = List.nth fl i in
467 Some (List.nth l recindex)
473 (match reduceaux [] recparam with
475 | C.Appl ((C.MutConstruct _)::_) ->
477 let counter = ref (List.length fl) in
479 (fun _ -> decr counter ; S.subst (C.Fix (!counter,fl)))
483 (* Possible optimization: substituting whd recparam in l *)
485 | _ -> if l = [] then t' () else C.Appl ((t' ())::l)
487 | None -> if l = [] then t' () else C.Appl ((t' ())::l)
493 (function (n,ty,bo) ->
494 (n,reduceaux [] ty, reduceaux [] bo)
499 if l = [] then t' else C.Appl (t'::l)