summaryrefslogtreecommitdiff
path: root/theory.ml
blob: 45a76f17d58fc934363e84f598824e10b6ba46ae (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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
(***************************************************************************)
(*  This is part of aac_tactics, it is distributed under the terms of the  *)
(*         GNU Lesser General Public License version 3                     *)
(*              (see file LICENSE for more details)                        *)
(*                                                                         *)
(*       Copyright 2009-2010: Thomas Braibant, Damien Pous.                *)
(***************************************************************************)

(** Constr from the theory of this particular development 

    The inner-working of this module is highly correlated with the
    particular structure of {b AAC.v}, therefore, it should
    be of little interest to most readers.
*)


open Term

let ac_theory_path = ["AAC"]

module Sigma = struct
  let sigma = lazy (Coq.init_constant ac_theory_path "sigma")
  let sigma_empty = lazy (Coq.init_constant ac_theory_path "sigma_empty")
  let sigma_add = lazy (Coq.init_constant ac_theory_path "sigma_add")
  let sigma_get = lazy (Coq.init_constant ac_theory_path "sigma_get")
    
  let add ty n x map = 
    mkApp (Lazy.force sigma_add,[|ty; n; x ;  map|])
  let empty ty =
    mkApp (Lazy.force sigma_empty,[|ty |])
  let typ ty = 
    mkApp (Lazy.force sigma, [|ty|])

  let to_fun ty null map = 
    mkApp (Lazy.force sigma_get, [|ty;null;map|])

  let of_list ty null l =
    let map =
      List.fold_left 
	(fun acc (i,t) -> assert (i > 0); add ty (Coq.Pos.of_int i) t acc) 
	(empty ty)
	l
    in to_fun ty null map 
end


module Sym = struct
  type pack = {ar: Term.constr; value: Term.constr ; morph: Term.constr}
  
  let path = ac_theory_path @ ["Sym"]
  let typ = lazy (Coq.init_constant path "pack")
  let mkPack = lazy (Coq.init_constant path "mkPack")
  let typeof = lazy (Coq.init_constant path "type_of") 
  let relof = lazy (Coq.init_constant path "rel_of") 
  let value = lazy (Coq.init_constant path "value")
  let null = lazy (Coq.init_constant path "null")
  let mk_typeof :  Coq.reltype -> int -> constr = fun (x,r) n ->
    mkApp (Lazy.force typeof, [| x ; Coq.Nat.of_int n |]) 
  let mk_relof :  Coq.reltype -> int -> constr = fun (x,r) n ->
    mkApp (Lazy.force relof, [| x;r ; Coq.Nat.of_int n |]) 
  let mk_pack ((x,r): Coq.reltype) s = 
    mkApp (Lazy.force mkPack, [|x;r; s.ar;s.value;s.morph|])
  let null eqt witness = 
    let (x,r),e = eqt in 
      mkApp (Lazy.force null, [| x;r;e;witness |])
	
end

module Sum = struct
  type pack = {plus: Term.constr; zero: Term.constr ; opac: Term.constr}

  let path = ac_theory_path @ ["Sum"]
  let typ = lazy (Coq.init_constant path "pack")
  let mkPack = lazy (Coq.init_constant path "mkPack")
  let cstr_zero = lazy (Coq.init_constant path "zero")
  let cstr_plus = lazy (Coq.init_constant path "plus")
    
  let mk_pack: Coq.reltype -> pack -> Term.constr = fun (x,r) s ->
    mkApp (Lazy.force mkPack , [| x ; r; s.plus; s.zero; s.opac|])
      
  let zero: Coq.reltype -> constr -> constr = fun (x,r) pack ->
    mkApp (Lazy.force cstr_zero, [| x;r;pack|])
  let plus: Coq.reltype -> constr -> constr = fun (x,r) pack ->
    mkApp (Lazy.force cstr_plus, [| x;r;pack|])


end

module Prd = struct
  type pack = {dot: Term.constr; one: Term.constr ; opa: Term.constr}

  let path = ac_theory_path @ ["Prd"]
  let typ = lazy (Coq.init_constant path "pack")
  let mkPack = lazy (Coq.init_constant path "mkPack")
  let cstr_one = lazy (Coq.init_constant path "one")
  let cstr_dot = lazy (Coq.init_constant path "dot")
    
  let mk_pack: Coq.reltype -> pack -> Term.constr = fun (x,r) s ->
    mkApp (Lazy.force mkPack , [| x ; r; s.dot; s.one; s.opa|])
  let one: Coq.reltype -> constr -> constr = fun (x,r) pack ->
    mkApp (Lazy.force cstr_one, [| x;r;pack|])
  let dot: Coq.reltype -> constr -> constr = fun (x,r) pack ->
    mkApp (Lazy.force cstr_dot, [| x;r;pack|])


end

  
let op_ac = lazy (Coq.init_constant ac_theory_path "Op_AC")
let op_a = lazy (Coq.init_constant ac_theory_path "Op_A")
  
(** The constants from the inductive type *)
let _Tty = lazy (Coq.init_constant ac_theory_path "T") 
let vTty = lazy (Coq.init_constant ac_theory_path "vT") 
  
let rsum = lazy (Coq.init_constant ac_theory_path "sum") 
let rprd = lazy (Coq.init_constant ac_theory_path "prd") 
let rsym = lazy (Coq.init_constant ac_theory_path "sym") 
let vnil = lazy (Coq.init_constant ac_theory_path "vnil") 
let vcons = lazy (Coq.init_constant ac_theory_path "vcons") 
let eval = lazy (Coq.init_constant ac_theory_path "eval")
let decide_thm = lazy (Coq.init_constant ac_theory_path "decide")

(** Rebuild an equality   *)
let mk_equal = fun (x,r) left right ->
  mkApp (r, [| left; right|]) 


let anomaly msg = 
  Util.anomaly ("aac_tactics: " ^ msg)

let user_error msg = 
  Util.error ("aac_tactics: " ^ msg)


module Trans = struct
  

  (** {1 From Coq to Abstract Syntax Trees (AST)}
      
      This module provides facilities to interpret a Coq term with
      arbitrary operators as an abstract syntax tree. Considering an
      application, we try to infer instances of our classes. We
      consider that raw morphisms ([Sym]) are coarser than [A]
      operators, which in turn are coarser than [AC] operators.  We
      need to treat the units first. Indeed, considering [S] as a
      morphism is problematic because [S O] is a unit.  
      
      During this reification, we gather some informations that will
      be used to rebuild Coq terms from AST ( type {!envs}) *)

  type pack = 
    | AC of Sum.pack 		(* the opac pack *)
    | A of Prd.pack 		(* the opa pack *)
    | Sym of Sym.pack       	(* the sym pack *)

  type head =
    | Fun  
    | Plus 
    | Dot  
    | One  
    | Zero


  (* discr is a map from {!Term.constr} to
     (head * pack).
     
     [None] means that it is not possible to instantiate this partial
     application to an interesting class.

     [Some x] means that we found something in the past. This means in
     particular that a single constr cannot be two things at the same
     time.
     
     However, for the transitivity process, we do not need to remember
     if the constr was the unit or the binary operation. We will use
     the projections from the module's record.
     
     The field [bloom] allows to give a unique number to each class we
     found.  *)
  type envs = 
      {
	discr : (constr , (head * pack) option) Hashtbl.t ; 
	
	bloom : (pack, int ) Hashtbl.t; 
	bloom_back  : (int, pack ) Hashtbl.t;
	bloom_next : int ref;
      }

  let empty_envs () = 
    {
      discr = Hashtbl.create 17;

      bloom  =  Hashtbl.create 17; 
      bloom_back  =  Hashtbl.create 17;  
      bloom_next = ref 1;
    }

  let add_bloom envs pack = 
    if Hashtbl.mem envs.bloom pack 
    then ()
    else
      let x = ! (envs.bloom_next) in 
	Hashtbl.add envs.bloom pack x;
	Hashtbl.add envs.bloom_back x pack;
	incr (envs.bloom_next)

  let find_bloom envs pack = 
    try Hashtbl.find envs.bloom pack
    with Not_found -> assert false


  (** try to infer the kind of operator we are dealing with *)
  let is_morphism  rlt papp ar goal =
    let typeof = Sym.mk_typeof rlt ar in 
    let relof = Sym.mk_relof rlt ar in 
    let env = Tacmach.pf_env goal in 
    let evar_map = Tacmach.project goal in 
    let m = Coq.Classes.mk_morphism  typeof relof  papp in
      try 
	let _ = Tacmach.pf_check_type goal papp typeof in 
	let evar_map,m = Typeclasses.resolve_one_typeclass env evar_map m in
	let pack = {Sym.ar = (Coq.Nat.of_int ar); Sym.value= papp; Sym.morph= m} in 
	  Some (Coq.goal_update goal evar_map, Fun , Sym pack) 
      with 
	| Not_found ->  None
	| _ ->  None
	    
  (** gives back the class  *)
  let is_op gl (rlt: Coq.reltype) pack op null = 
    let (x,r) = rlt in 
    let ty = mkApp (pack ,[|x;r; op; null |]) in
    let env = Tacmach.pf_env gl in 
    let evar_map = Tacmach.project gl in 
      try 
	let em,t = Typeclasses.resolve_one_typeclass env evar_map ty in
	let op = Evarutil.nf_evar em op in 
	let null = Evarutil.nf_evar em null in 
	  Some (Coq.goal_update gl em,t,op,null)
      with Not_found -> None


  let is_plus  (rlt: Coq.reltype) plus goal=
    let (zero,goal) = Coq.evar_unit goal rlt in
      match is_op goal rlt (Lazy.force op_ac) plus zero
      with
	| None -> None
	| Some (gl,s,plus,zero) -> 
	    let pack = {Sum.plus=plus;Sum.zero=zero;Sum.opac=s} in 
	      Some (gl, Plus , AC pack)

  let is_dot rlt dot goal=
    let (one,goal) = Coq.evar_unit goal rlt in
      match is_op goal rlt (Lazy.force op_a) dot one
      with
	| None -> None
	| Some (goal,s,dot,one) -> 
	    let pack = {Prd.dot=dot;Prd.one=one;Prd.opa=s} in 
	      Some (goal, Dot,  A pack)

  let is_zero rlt zero goal =
    let (plus,goal) = Coq.evar_binary goal rlt in
      match is_op goal rlt (Lazy.force op_ac) plus zero
      with
	| None -> None
	| Some (goal,s,plus,zero) -> 
	    let pack = {Sum.plus=plus;Sum.zero=zero;Sum.opac=s} in 
	      Some (goal, Zero , AC pack)

  let is_one  rlt one goal =
    let (dot,goal) = Coq.evar_binary goal rlt in
      match is_op goal rlt (Lazy.force op_a) dot one
      with 
	| None -> None 
	| Some (goal,s,dot,one)-> 
	    let pack = {Prd.dot=dot;Prd.one=one;Prd.opa=s} in 
	      Some (goal, One, A pack)


  let (>>) x y a =
    match x a with | None -> y a | x -> x

  let is_unit rlt papp =
    (is_zero rlt papp )>> (is_one rlt papp)
	
  let what_is_it rlt papp ar goal : 
      (Coq.goal_sigma * head * pack ) option =
    match ar  with 
      | 2 -> 
	  begin
	    (
	      (is_plus rlt papp)>>
		(is_dot rlt papp)>>
		(is_morphism rlt papp ar)
	    )	goal
	  end
      | _ -> 
	  is_morphism rlt papp ar goal

    

	
  (** [discriminates goal envs rlt t ca] infer :
      
      - the nature of the application [t ca] (is the head symbol a
      Plus, a Dot, so on), 

      - its {! pack } (is it an AC operator, or an A operator, or a
      Symbol ?),

      - the relevant partial application,

      - the vector of the remaining arguments

      We use an expansion to handle the special case of units, before
      going back to the general discrimination procedure *)
  let discriminate goal envs (rlt : Coq.reltype) t ca : Coq.goal_sigma * head * pack * constr * constr array =   
    let nb_params = Array.length ca in
    let f cont x p_app ar = 
      assert (0 <= ar && ar <= nb_params);
      match x with
	| Some (goal, discr, pack) -> 
	    Hashtbl.add envs.discr p_app (Some (discr, pack));
	    add_bloom envs pack;
	    (goal, discr, pack, p_app, Array.sub ca (nb_params-ar) ar)
	| None -> 
	    begin
	      (* to memoise the failures *)
	      Hashtbl.add envs.discr p_app None;
	      (* will terminate, since [const] is
		 capped, and it is easy to find an
		 instance of a constant *)
	      cont goal (ar-1)
	    end
    in
    let rec aux goal ar :Coq.goal_sigma * head * pack * constr * constr array = 
      assert (0 <= ar && ar <= nb_params);
      let p_app = mkApp (t, Array.sub ca 0 (nb_params - ar)) in 	
	begin	
	  try 
	    begin match Hashtbl.find envs.discr p_app with 
	      | None -> aux goal  (ar-1)
	      | Some (discr,sym) -> 
		  goal,
		  discr, 
		  sym, 
		  p_app, 
		  Array.sub ca (nb_params -ar ) ar
	    end
	  with
	      Not_found -> (* Could not find this constr *)		
		f aux (what_is_it rlt p_app ar goal) p_app ar
	end
    in
      match is_unit rlt (mkApp (t,ca)) goal with 
	| None -> aux goal (nb_params)
	| x ->  f (fun _ -> assert false) x (mkApp (t,ca)) 0

  let discriminate goal envs rlt  x =
    try 
      match Coq.decomp_term x with 
	| Var _ -> 
	    discriminate goal envs rlt  x [| |]		
	| App (t,ca) -> 
	    discriminate goal envs rlt   t ca
	| Construct c ->  
	    discriminate goal envs rlt  x [| |]		
	| _ -> 
	    assert false
    with 
	(* TODO: is it the only source of invalid use that fall into
	   this catch_all ? *)
	e -> user_error "cannot handle this kind of hypotheses (higher order function symbols, variables occuring under a non-morphism, etc)."


  (** [t_of_constr goal rlt envs cstr] builds the abstract syntax
      tree of the term [cstr]. Doing so, it modifies the environment
      of known stuff [envs], and eventually creates fresh
      evars. Therefore, we give back the goal updated accordingly *)
  let t_of_constr goal (rlt: Coq.reltype ) envs  : constr -> Matcher.Terms.t *Coq.goal_sigma =
    let r_evar_map = ref (goal) in 
    let rec aux x = 
      match Coq.decomp_term x with 
	| Rel i -> Matcher.Terms.Var i
	| _ -> 
	    let goal, sym, pack , p_app, ca = discriminate (!r_evar_map) envs rlt   x in 
	      r_evar_map := goal;
	      let k = find_bloom envs pack
	      in 
		match sym with 
		  | Plus ->
		      assert (Array.length ca = 2);
		      Matcher.Terms.Plus ( k, aux ca.(0), aux ca.(1))
		  | Zero  -> 
		      assert (Array.length ca = 0);
		      Matcher.Terms.Zero ( k)
		  | Dot  -> 
		      assert (Array.length ca = 2);			  
		      Matcher.Terms.Dot ( k, aux ca.(0), aux ca.(1))
		  | One  -> 
		      assert (Array.length ca = 0);
		      Matcher.Terms.One ( k)
		  | Fun  ->
		      Matcher.Terms.Sym ( k, Array.map aux ca)		
    in 
      (
	fun x -> let r = aux x in r,  !r_evar_map 
      ) 
	
  (** {1 From AST back to Coq }
      
      The next functions allow one to map OCaml abstract syntax trees
      to Coq terms *)

 (** {2 Building raw, natural, terms} *)

  (** [raw_constr_of_t] rebuilds a term in the raw representation *)
  let raw_constr_of_t envs (rlt : Coq.reltype)  (t : Matcher.Terms.t) : Term.constr =
    let add_set,get = 
      let r = ref [] in 
      let rec add x = function 
	  [ ] -> [x]
	| t::q when t = x -> t::q
	| t::q -> t:: (add x q) 
      in 
	(fun x -> r := add x !r),(fun () -> !r)
    in
    let rec aux t =
      match t with 
	| Matcher.Terms.Plus (s,l,r) ->
	    begin match Hashtbl.find envs.bloom_back s with 
	      | AC s -> 
		  mkApp (s.Sum.plus ,  [|(aux l);(aux r)|])
	      | _ -> assert false
	    end
	| Matcher.Terms.Dot (s,l,r) ->
	    begin match Hashtbl.find envs.bloom_back s with 
	      | A s -> 
		  mkApp (s.Prd.dot,  [|(aux l);(aux r)|])
	      | _ -> assert false
	    end
	| Matcher.Terms.Sym (s,t) ->
	    begin match Hashtbl.find envs.bloom_back s with 
	      | Sym s -> 
		  mkApp (s.Sym.value, Array.map aux t)
	      | _ -> assert false
	    end
	| Matcher.Terms.One x ->
	    begin match Hashtbl.find envs.bloom_back x with 
	      | A s -> 
		  s.Prd.one
	      | _ -> assert false
	    end
	| Matcher.Terms.Zero  x ->
	    begin match Hashtbl.find envs.bloom_back x with 
	      | AC s -> 
		  s.Sum.zero 
	      | _ -> assert false
	    end
	| Matcher.Terms.Var i -> add_set i;
	    let i = (Names.id_of_string (Printf.sprintf "x%i" i)) in 
	      mkVar (i)
    in 
    let x = fst rlt in 
    let rec cap c = function [] -> c
      | t::q ->  let i = (Names.id_of_string (Printf.sprintf "x%i" t)) in 
	  cap (mkNamedProd i x c) q
    in
      cap ((aux t)) (get ())
	(* aux t is possible for printing only, but I wonder what
	   would be the status of such a term*)
	

  (** {2 Building reified terms} *)
	
  (* Some informations to be able to build the maps  *)
  type reif_params = 
      {
	a_null : constr;
	ac_null : constr;	
	sym_null : constr;
	a_ty : constr;
	ac_ty : constr;	
	sym_ty : constr;
      }

 type sigmas = {
    env_sym : Term.constr;
    env_sum : Term.constr;
    env_prd : Term.constr;
  }
  (** A record containing the environments that will be needed by the
      decision procedure, as a Coq constr. Contains also the functions
      from the symbols (as ints) to indexes (as constr) *)
  type sigma_maps = {
    sym_to_pos : int -> Term.constr;
    sum_to_pos : int -> Term.constr;
    prd_to_pos : int -> Term.constr;
  }

  (* convert the [envs] into the [sigma_maps] *)
  let envs_to_list rlt envs = 
    let add x y (n,l) = (n+1, (x, ( n, y))::l) in 
    let  nil = 1,[]in 
      Hashtbl.fold 
	(fun int pack (sym,sum,prd) -> 
	   match pack with 
	     |AC s -> 
		let s = Sum.mk_pack rlt s in 
		  sym, add (int) s sum, prd
	     |A s -> 
		let s = Prd.mk_pack rlt s in 
		  sym, sum, add (int) s prd
	     | Sym s ->
		 let s = Sym.mk_pack rlt s in 
		   add (int) s sym, sum, prd
	)  
	envs.bloom_back  
	(nil,nil,nil)



  (** infers some stuff that will be required when we will build
      environments (our environments need a default case, so we need
      an Op_AC, an Op_A, and a symbol) *)

  (* Note : this function can fail if the user is using the wrong
     relation, like proving a = b, while the classes are defined with
     another relation (==) 
  *)
  let build_reif_params goal eqt = 
    let rlt = fst eqt in 
    let  plus,goal = Coq.evar_binary goal rlt in 
    let  dot ,goal =  Coq.evar_binary goal rlt in 
    let  one ,goal = Coq.evar_unit goal rlt in 
    let  zero,goal  =  Coq.evar_unit goal rlt in  

    let (x,r) = rlt in 
    let ty_ac = ( mkApp (Lazy.force op_ac, [| x;r;plus;zero|])) in
    let ty_a = ( mkApp (Lazy.force op_a, [| x;r;dot;one|])) in
    let a  ,goal= 
      try Coq.resolve_one_typeclass goal ty_a 
      with Not_found -> user_error ("Unable to infer a default A operator.") 
    in
    let ac ,goal= 
      try Coq.resolve_one_typeclass goal ty_ac 
      with Not_found ->  user_error ("Unable to infer a default AC operator.")
    in 
    let plus = Coq.nf_evar goal plus  in 
    let dot =  Coq.nf_evar goal dot  in 
    let one =  Coq.nf_evar goal one  in 
    let zero = Coq.nf_evar goal zero  in 

    let record = 
      {a_null = Prd.mk_pack rlt {Prd.dot=dot;Prd.one=one;Prd.opa=a};
       ac_null= Sum.mk_pack rlt {Sum.plus=plus;Sum.zero=zero;Sum.opac=ac}; 
       sym_null = Sym.null eqt zero;
       a_ty   = (mkApp (Lazy.force Prd.typ, [| x;r; |]));
       ac_ty = ( mkApp (Lazy.force Sum.typ, [| x;r|])); 
       sym_ty =  mkApp (Lazy.force Sym.typ, [|x;r|])
      } 
    in 
      goal,     record

  (** [build_sigma_maps] given a envs and some reif_params, we are
      able to build the sigmas *)
  let build_sigma_maps goal eqt envs : sigmas * sigma_maps *  Proof_type.goal Evd.sigma =
    let rlt = fst eqt in 
    let goal,rp = build_reif_params goal eqt in 
    let ((_,sym), (_,sum),(_,prd)) = envs_to_list rlt envs in 
    let f = List.map (fun (x,(y,z)) -> (x,Coq.Pos.of_int y)) in 
    let g = List.map (fun (x,(y,z)) -> (y,z)) in 
    let sigmas = 
      {env_sym = Sigma.of_list rp.sym_ty rp.sym_null (g sym);
       env_sum = Sigma.of_list rp.ac_ty rp.ac_null (g sum);
       env_prd = Sigma.of_list rp.a_ty rp.a_null (g prd);
      } in 
    let sigma_maps = { 
      sym_to_pos = (let sym = f sym in fun x ->  (List.assoc x sym));
      sum_to_pos = (let sum = f sum in fun x ->  (List.assoc x sum));
      prd_to_pos = (let prd = f prd in fun x ->  (List.assoc x prd));
    }
    in 
      sigmas, sigma_maps , goal 
	


  (** builders for the reification *)
  type reif_builders =
      {
	rsum: constr -> constr -> constr -> constr;
	rprd: constr -> constr -> constr -> constr;
	rzero: constr -> constr;
	rone: constr -> constr;
	rsym: constr -> constr array -> constr
      }

  (* donne moi une tactique, je rajoute ma part.  Potentiellement, il
     est possible d'utiliser la notation 'do' a la Haskell:
     http://www.cas.mcmaster.ca/~carette/pa_monad/ *)
  let (>>) : 'a * Proof_type.tactic -> ('a -> 'b * Proof_type.tactic) -> 'b * Proof_type.tactic = 
    fun (x,t) f ->
      let b,t' = f x in 
	b, Tacticals.tclTHEN t t'
	  
  let return x = x, Tacticals.tclIDTAC
    
  let mk_vect vnil vcons v =
    let ar = Array.length v in 
    let rec aux = function 
      | 0 ->  vnil
      | n  -> let n = n-1 in 
	  mkApp( vcons, 
 		 [| 
		   (Coq.Nat.of_int n);
		   v.(ar - 1 - n);
		   (aux (n))
		 |]	
	       )
    in aux ar
	 
  (* TODO: use a do notation *)
  let mk_reif_builders  (rlt: Coq.reltype)   (env_sym:constr)  :reif_builders*Proof_type.tactic =
    let x,r = rlt in 
    let tty =  mkApp (Lazy.force _Tty, [| x ; r ; env_sym|]) in 
      (Coq.mk_letin'  "mk_rsum" (mkApp (Lazy.force rsum, [| x; r;  env_sym|]))) >>
      (fun rsum -> (Coq.mk_letin' "mk_rprd" (mkApp (Lazy.force rprd, [| x; r; env_sym|]))) 
	 >> fun rprd -> ( Coq.mk_letin' "mk_rsym" (mkApp (Lazy.force rsym, [| x;r; env_sym|]))) 
	   >> fun rsym -> (Coq.mk_letin' "mk_vnil" (mkApp (Lazy.force vnil, [| x;r; env_sym|])))
	     >> fun vnil -> Coq.mk_letin' "mk_vcons" (mkApp (Lazy.force vcons, [| x;r; env_sym|]))	
	       >> fun vcons ->     
		 return {
		   rsum = 
		     begin fun idx l r ->
		       mkApp (rsum, [|  idx ; Coq.mk_mset tty [l,1 ; r,1]|])
		     end;
		   rzero =
		     begin fun idx  ->  
		       mkApp (rsum, [|  idx ; Coq.mk_mset tty []|]) 
		     end;
		   rprd = 
		     begin fun idx l r ->
		       let lst = Coq.List.of_list tty [l;r] in
			 mkApp (rprd, [| idx; lst|]) 
		     end;
		   rone =   
		     begin fun idx ->
		       let lst = Coq.List.of_list tty [] in 
			 mkApp (rprd, [| idx; lst|]) end;
		   rsym = 
		     begin fun idx v ->
		       let vect = mk_vect vnil vcons  v in
			 mkApp (rsym, [| idx; vect|])
		     end;
		 }
      )
      


  type reifier = sigma_maps * reif_builders

  let  mk_reifier eqt envs goal :  sigmas * reifier * Proof_type.tactic = 
    let s, sm, goal = build_sigma_maps goal eqt envs in 
    let env_sym, env_sym_letin = Coq.mk_letin "env_sym_name" (s.env_sym) in 
    let env_prd, env_prd_letin = Coq.mk_letin "env_prd_name" (s.env_prd) in 
    let env_sum, env_sum_letin = Coq.mk_letin "env_sum_name" (s.env_sum) in
    let s = {env_sym = env_sym; env_prd = env_prd; env_sum = env_sum} in 
    let rb , tac = mk_reif_builders (fst eqt) (s.env_sym) in 
    let evar_map = Tacmach.project goal in
    let tac = Tacticals.tclTHENLIST (
      [		       Refiner.tclEVARS evar_map;
		       env_prd_letin ;
		       env_sum_letin ;
		       env_sym_letin ;
		       tac
      ]) in 
      s, (sm, rb), tac
	
	
  (** [reif_constr_of_t reifier t] rebuilds the term [t] in the
      reified form. We use the [reifier] to minimise the size of the
      terms (we make as much lets as possible)*)
  let reif_constr_of_t (sm,rb) (t:Matcher.Terms.t) : constr =
    let rec aux = function
      | Matcher.Terms.Plus (s,l,r) ->
	  let idx = sm.sum_to_pos s  in
	    rb.rsum idx (aux l) (aux r) 
      | Matcher.Terms.Dot (s,l,r) ->
	  let idx = sm.prd_to_pos s in 
	    rb.rprd idx (aux l) (aux r) 
      | Matcher.Terms.Sym (s,t) ->
	  let idx =  sm.sym_to_pos  s in 
	    rb.rsym idx (Array.map aux t)
      | Matcher.Terms.One s ->
	  let idx = sm.prd_to_pos s in 
	    rb.rone idx
      | Matcher.Terms.Zero s ->
	  let idx = sm.sum_to_pos s in 
	    rb.rzero idx
      | Matcher.Terms.Var i -> 
	  anomaly "call to reif_constr_of_t on a term with variables."
    in aux t


end