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

« back to all changes in this revision

Viewing changes to tactics/refine.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: refine.ml 12187 2009-06-13 19:36:59Z msozeau $ *)
 
10
 
 
11
(* JCF -- 6 janvier 1998  EXPERIMENTAL *)
 
12
 
 
13
(*
 
14
 *  L'id�e est, en quelque sorte, d'avoir de "vraies" m�tavariables
 
15
 *  dans Coq, c'est-�-dire de donner des preuves incompl�tes -- mais
 
16
 *  o� les trous sont typ�s -- et que les sous-buts correspondants
 
17
 *  soient engendr�s pour finir la preuve.
 
18
 *
 
19
 *  Exemple : 
 
20
 *    J'ai le but
 
21
 *        (x:nat) { y:nat | (minus y x) = x }
 
22
 *    et je donne la preuve incompl�te
 
23
 *        [x:nat](exist nat [y:nat]((minus y x)=x) (plus x x) ?)
 
24
 *    ce qui engendre le but
 
25
 *        (minus (plus x x) x)=x
 
26
 *)
 
27
 
 
28
(*  Pour cela, on proc�de de la mani�re suivante :
 
29
 *
 
30
 *  1. Un terme de preuve incomplet est un terme contenant des variables
 
31
 *     existentielles Evar i.e. "?" en syntaxe concr�te.
 
32
 *     La r�solution de ces variables n'est plus n�cessairement totale
 
33
 *     (ise_resolve called with fail_evar=false) et les variables
 
34
 *     existentielles restantes sont remplac�es par des m�ta-variables
 
35
 *     cast�es par leur types (celui est connu : soit donn�, soit trouv�
 
36
 *     pendant la phase de r�solution).
 
37
 *
 
38
 *  2. On met ensuite le terme "� plat" i.e. on n'autorise des MV qu'au
 
39
 *     permier niveau et pour chacune d'elles, si n�cessaire, on donne
 
40
 *     � son tour un terme de preuve incomplet pour la r�soudre.
 
41
 *     Exemple: le terme (f a ? [x:nat](e ?)) donne
 
42
 *         (f a ?1 ?2) avec ?2 => [x:nat]?3 et ?3 => (e ?4)
 
43
 *         ?1 et ?4 donneront des buts
 
44
 *
 
45
 *  3. On �crit ensuite une tactique tcc qui engendre les sous-buts
 
46
 *     � partir d'une preuve incompl�te.
 
47
 *)
 
48
 
 
49
open Pp
 
50
open Util
 
51
open Names
 
52
open Term
 
53
open Termops
 
54
open Tacmach
 
55
open Sign
 
56
open Environ
 
57
open Reduction
 
58
open Typing
 
59
open Tactics
 
60
open Tacticals
 
61
open Printer
 
62
 
 
63
type term_with_holes = TH of constr * metamap * sg_proofs
 
64
and  sg_proofs       = (term_with_holes option) list
 
65
 
 
66
(* pour debugger *)
 
67
 
 
68
let rec pp_th (TH(c,mm,sg)) =
 
69
  (str"TH=[ " ++ hov 0 (pr_lconstr c ++ fnl () ++
 
70
                              (* pp_mm mm ++ fnl () ++ *)
 
71
                           pp_sg sg) ++ str "]")
 
72
and pp_mm l =
 
73
  hov 0 (prlist_with_sep (fun _ -> (fnl ())) 
 
74
           (fun (n,c) -> (int n ++ str" --> " ++ pr_lconstr c)) l)
 
75
and pp_sg sg =
 
76
  hov 0 (prlist_with_sep (fun _ -> (fnl ()))
 
77
           (function None -> (str"None") | Some th -> (pp_th th)) sg)
 
78
     
 
79
(*  compute_metamap : constr -> 'a evar_map -> term_with_holes
 
80
 *  r�alise le 2. ci-dessus
 
81
 *
 
82
 *  Pour cela, on renvoie une meta_map qui indique pour chaque meta-variable
 
83
 *  si elle correspond � un but (None) ou si elle r�duite � son tour
 
84
 *  par un terme de preuve incomplet (Some c).
 
85
 *
 
86
 *  On a donc l'INVARIANT suivant : le terme c rendu est "de niveau 1"
 
87
 *  -- i.e. � plat -- et la meta_map contient autant d'�l�ments qu'il y 
 
88
 *  a de meta-variables dans c. On suppose de plus que l'ordre dans la
 
89
 *  meta_map correspond � celui des buts qui seront engendr�s par le refine.
 
90
 *)
 
91
 
 
92
let replace_by_meta env sigma = function
 
93
  | TH (m, mm, sgp) when isMeta (strip_outer_cast m) -> m,mm,sgp
 
94
  | (TH (c,mm,_)) as th ->
 
95
      let n = Evarutil.new_meta() in
 
96
      let m = mkMeta n in
 
97
      (* quand on introduit une mv on calcule son type *)
 
98
      let ty = match kind_of_term c with
 
99
        | Lambda (Name id,c1,c2) when isCast c2 ->
 
100
            let _,_,t = destCast c2 in mkNamedProd id c1 t
 
101
        | Lambda (Anonymous,c1,c2) when isCast c2 ->
 
102
            let _,_,t = destCast c2 in mkArrow c1 t
 
103
        | _ -> (* (App _ | Case _) -> *)
 
104
            Retyping.get_type_of_with_meta env sigma mm c
 
105
        (*
 
106
        | Fix ((_,j),(v,_,_)) ->
 
107
            v.(j) (* en pleine confiance ! *)
 
108
        | _ -> invalid_arg "Tcc.replace_by_meta (TO DO)" 
 
109
        *)
 
110
      in
 
111
      mkCast (m,DEFAULTcast, ty),[n,ty],[Some th]
 
112
 
 
113
exception NoMeta
 
114
 
 
115
let replace_in_array keep_length env sigma a =
 
116
  if array_for_all (function (TH (_,_,[])) -> true | _ -> false) a then
 
117
    raise NoMeta;
 
118
  let a' = Array.map (function
 
119
                        | (TH (c,mm,[])) when not keep_length -> c,mm,[]
 
120
                        | th -> replace_by_meta env sigma th) a 
 
121
  in
 
122
  let v' = Array.map pi1 a' in
 
123
  let mm = Array.fold_left (@) [] (Array.map pi2 a') in
 
124
  let sgp = Array.fold_left (@) [] (Array.map pi3 a') in
 
125
  v',mm,sgp
 
126
    
 
127
let fresh env n =
 
128
  let id = match n with Name x -> x | _ -> id_of_string "_H" in
 
129
  next_global_ident_away true id (ids_of_named_context (named_context env))
 
130
 
 
131
let rec compute_metamap env sigma c = match kind_of_term c with
 
132
  (* le terme est directement une preuve *)
 
133
  | (Const _ | Evar _ | Ind _ | Construct _ |
 
134
    Sort _ | Var _ | Rel _) -> 
 
135
      TH (c,[],[])
 
136
 
 
137
  (* le terme est une mv => un but *)
 
138
  | Meta n ->
 
139
      TH (c,[],[None])
 
140
 
 
141
  | Cast (m,_, ty) when isMeta m -> 
 
142
      TH (c,[destMeta m,ty],[None])
 
143
 
 
144
 
 
145
  (* abstraction => il faut d�composer si le terme dessous n'est pas pur
 
146
   *    attention : dans ce cas il faut remplacer (Rel 1) par (Var x)
 
147
   *    o� x est une variable FRAICHE *)
 
148
  | Lambda (name,c1,c2) ->
 
149
      let v = fresh env name in
 
150
      let env' = push_named (v,None,c1) env in
 
151
      begin match compute_metamap env' sigma (subst1 (mkVar v) c2) with
 
152
        (* terme de preuve complet *)
 
153
        | TH (_,_,[]) -> TH (c,[],[])
 
154
        (* terme de preuve incomplet *)    
 
155
        | th ->
 
156
            let m,mm,sgp = replace_by_meta env' sigma th in
 
157
            TH (mkLambda (Name v,c1,m), mm, sgp)
 
158
      end
 
159
 
 
160
  | LetIn (name, c1, t1, c2) ->
 
161
      let v = fresh env name in
 
162
      let th1 = compute_metamap env sigma c1 in
 
163
      let env' = push_named (v,Some c1,t1) env in
 
164
      let th2 = compute_metamap env' sigma (subst1 (mkVar v) c2) in
 
165
      begin match th1,th2 with
 
166
        (* terme de preuve complet *)
 
167
        | TH (_,_,[]), TH (_,_,[]) -> TH (c,[],[])
 
168
        (* terme de preuve incomplet *)    
 
169
        | TH (c1,mm1,sgp1), TH (c2,mm2,sgp2) ->
 
170
            let m1,mm1,sgp1 =
 
171
              if sgp1=[] then (c1,mm1,[]) 
 
172
              else replace_by_meta env sigma th1 in
 
173
            let m2,mm2,sgp2 =
 
174
              if sgp2=[] then (c2,mm2,[]) 
 
175
              else replace_by_meta env' sigma th2 in
 
176
            TH (mkNamedLetIn v m1 t1 m2, mm1@mm2, sgp1@sgp2)
 
177
      end
 
178
 
 
179
  (* 4. Application *)
 
180
  | App (f,v) ->
 
181
      let a = Array.map (compute_metamap env sigma) (Array.append [|f|] v) in
 
182
      begin
 
183
        try
 
184
          let v',mm,sgp = replace_in_array false env sigma a in
 
185
          let v'' = Array.sub v' 1 (Array.length v) in
 
186
          TH (mkApp(v'.(0), v''),mm,sgp)
 
187
        with NoMeta ->
 
188
          TH (c,[],[])
 
189
      end
 
190
 
 
191
  | Case (ci,p,cc,v) ->
 
192
      (* bof... *)
 
193
      let nbr = Array.length v in
 
194
      let v = Array.append [|p;cc|] v in
 
195
      let a = Array.map (compute_metamap env sigma) v in
 
196
      begin
 
197
        try
 
198
          let v',mm,sgp = replace_in_array false env sigma a in
 
199
          let v'' = Array.sub v' 2 nbr in
 
200
          TH (mkCase (ci,v'.(0),v'.(1),v''),mm,sgp)
 
201
        with NoMeta ->
 
202
          TH (c,[],[])
 
203
      end
 
204
 
 
205
  (* 5. Fix. *)
 
206
  | Fix ((ni,i),(fi,ai,v)) ->
 
207
      (* TODO: use a fold *)
 
208
      let vi = Array.map (fresh env) fi in
 
209
      let fi' = Array.map (fun id -> Name id) vi in
 
210
      let env' = push_named_rec_types (fi',ai,v) env in
 
211
      let a = Array.map
 
212
                (compute_metamap env' sigma)
 
213
                (Array.map (substl (List.map mkVar (Array.to_list vi))) v) 
 
214
      in
 
215
      begin
 
216
        try
 
217
          let v',mm,sgp = replace_in_array true env' sigma a in
 
218
          let fix = mkFix ((ni,i),(fi',ai,v')) in
 
219
          TH (fix,mm,sgp)
 
220
        with NoMeta ->
 
221
          TH (c,[],[])
 
222
      end
 
223
              
 
224
  (* Cast. Est-ce bien exact ? *)
 
225
  | Cast (c,_,t) -> compute_metamap env sigma c
 
226
      (*let TH (c',mm,sgp) = compute_metamap sign c in
 
227
        TH (mkCast (c',t),mm,sgp) *)
 
228
      
 
229
  (* Produit. Est-ce bien exact ? *)
 
230
  | Prod (_,_,_) ->
 
231
      if occur_meta c then
 
232
        error "refine: proof term contains metas in a product."
 
233
      else
 
234
        TH (c,[],[])
 
235
 
 
236
  (* Cofix. *)
 
237
  | CoFix (i,(fi,ai,v)) ->
 
238
      let vi = Array.map (fresh env) fi in
 
239
      let fi' = Array.map (fun id -> Name id) vi in
 
240
      let env' = push_named_rec_types (fi',ai,v) env in
 
241
      let a = Array.map
 
242
                (compute_metamap env' sigma)
 
243
                (Array.map (substl (List.map mkVar (Array.to_list vi))) v) 
 
244
      in
 
245
      begin
 
246
        try
 
247
          let v',mm,sgp = replace_in_array true env' sigma a in
 
248
          let cofix = mkCoFix (i,(fi',ai,v')) in
 
249
          TH (cofix,mm,sgp)
 
250
        with NoMeta ->
 
251
          TH (c,[],[])
 
252
      end
 
253
 
 
254
 
 
255
(*  tcc_aux : term_with_holes -> tactic
 
256
 * 
 
257
 *  R�alise le 3. ci-dessus
 
258
 *)
 
259
 
 
260
let rec tcc_aux subst (TH (c,mm,sgp) as _th) gl =
 
261
  let c = substl subst c in
 
262
  match (kind_of_term c,sgp) with
 
263
    (* mv => sous-but : on ne fait rien *)
 
264
    | Meta _ , _ ->
 
265
        tclIDTAC gl
 
266
 
 
267
    | Cast (c,_,_), _ when isMeta c ->
 
268
        tclIDTAC gl
 
269
          
 
270
    (* terme pur => refine *)
 
271
    | _,[] ->
 
272
        refine c gl
 
273
        
 
274
    (* abstraction => intro *)
 
275
    | Lambda (Name id,_,m), _ ->
 
276
        assert (isMeta (strip_outer_cast m));
 
277
        begin match sgp with
 
278
          | [None] -> intro_mustbe_force id gl
 
279
          | [Some th] ->
 
280
              tclTHEN (introduction id)
 
281
                (onLastHyp (fun id -> tcc_aux (mkVar id::subst) th)) gl
 
282
          | _ -> assert false
 
283
        end
 
284
 
 
285
    | Lambda (Anonymous,_,m), _ -> (* if anon vars are allowed in evars *)
 
286
        assert (isMeta (strip_outer_cast m));
 
287
        begin match sgp with
 
288
          | [None] -> tclTHEN intro (onLastHyp (fun id -> clear [id])) gl
 
289
          | [Some th] ->
 
290
              tclTHEN
 
291
                intro
 
292
                (onLastHyp (fun id -> 
 
293
                  tclTHEN
 
294
                    (clear [id])
 
295
                    (tcc_aux (mkVar (*dummy*) id::subst) th))) gl
 
296
          | _ -> assert false
 
297
        end
 
298
 
 
299
    (* let in without holes in the body => possibly dependent intro *)
 
300
    | LetIn (Name id,c1,t1,c2), _ when not (isMeta (strip_outer_cast c1)) ->
 
301
        let c = pf_concl gl in
 
302
        let newc = mkNamedLetIn id c1 t1 c in
 
303
        tclTHEN 
 
304
          (change_in_concl None newc) 
 
305
          (match sgp with 
 
306
             | [None] -> introduction id
 
307
             | [Some th] ->
 
308
                 tclTHEN (introduction id)
 
309
                   (onLastHyp (fun id -> tcc_aux (mkVar id::subst) th))
 
310
             | _ -> assert false) 
 
311
          gl
 
312
 
 
313
    (* let in with holes in the body => unable to handle dependency
 
314
       because of evars limitation, use non dependent assert instead *)
 
315
    | LetIn (Name id,c1,t1,c2), _ ->
 
316
        tclTHENS
 
317
          (assert_tac (Name id) t1) 
 
318
          [(match List.hd sgp with 
 
319
             | None -> tclIDTAC
 
320
             | Some th -> onLastHyp (fun id -> tcc_aux (mkVar id::subst) th));
 
321
           (match List.tl sgp with 
 
322
             | [] -> refine (subst1 (mkVar id) c2)  (* a complete proof *)
 
323
             | [None] -> tclIDTAC                   (* a meta *)
 
324
             | [Some th] ->                         (* a partial proof *)
 
325
                 onLastHyp (fun id -> tcc_aux (mkVar id::subst) th)
 
326
             | _ -> assert false)]
 
327
          gl
 
328
 
 
329
    (* fix => tactique Fix *)
 
330
    | Fix ((ni,j),(fi,ai,_)) , _ ->
 
331
        let out_name = function
 
332
          | Name id -> id
 
333
          | _ -> error "Recursive functions must have names."
 
334
        in
 
335
        let fixes = array_map3 (fun f n c -> (out_name f,succ n,c)) fi ni ai in
 
336
        let firsts,lasts = list_chop j (Array.to_list fixes) in
 
337
        tclTHENS
 
338
          (mutual_fix_with_index 
 
339
            (out_name fi.(j)) (succ ni.(j)) (firsts@List.tl lasts) j)
 
340
          (List.map (function
 
341
                       | None -> tclIDTAC 
 
342
                       | Some th -> tcc_aux subst th) sgp)
 
343
          gl
 
344
 
 
345
    (* cofix => tactique CoFix *)
 
346
    | CoFix (j,(fi,ai,_)) , _ ->
 
347
        let out_name = function
 
348
          | Name id -> id
 
349
          | _ -> error "Recursive functions must have names."
 
350
        in
 
351
        let cofixes = array_map2 (fun f c -> (out_name f,c)) fi ai in
 
352
        let firsts,lasts = list_chop j (Array.to_list cofixes) in
 
353
        tclTHENS
 
354
          (mutual_cofix_with_index (out_name fi.(j)) (firsts@List.tl lasts) j)
 
355
          (List.map (function
 
356
                       | None -> tclIDTAC 
 
357
                       | Some th -> tcc_aux subst th) sgp)
 
358
          gl
 
359
 
 
360
    (* sinon on fait refine du terme puis appels rec. sur les sous-buts.
 
361
     * c'est le cas pour App et MutCase. *)
 
362
    | _ ->
 
363
        tclTHENS
 
364
          (refine c)
 
365
          (List.map
 
366
            (function None -> tclIDTAC | Some th -> tcc_aux subst th) sgp)
 
367
          gl
 
368
 
 
369
(* Et finalement la tactique refine elle-m�me : *)
 
370
 
 
371
let refine (evd,c) gl =
 
372
  let sigma = project gl in
 
373
  let evd = Evd.evars_of (Typeclasses.resolve_typeclasses
 
374
                             ~onlyargs:true ~fail:false (pf_env gl) 
 
375
                             (Evd.create_evar_defs evd)) 
 
376
  in
 
377
  let c = Evarutil.nf_evar evd c in
 
378
  let (evd,c) = Evarutil.evars_to_metas sigma (evd,c) in
 
379
  (* Relies on Cast's put on Meta's by evars_to_metas, because it is otherwise 
 
380
     complicated to update meta types when passing through a binder *)
 
381
  let th = compute_metamap (pf_env gl) evd c in
 
382
  tclTHEN (Refiner.tclEVARS evd) (tcc_aux [] th) gl