summaryrefslogtreecommitdiff
path: root/kernel/vconv.ml
blob: 653f8978c8c7e0c5dd88e4b7b170290335fdaea7 (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
open Names
open Declarations
open Term
open Environ
open Conv_oracle
open Reduction 
open Closure
open Vm
open Csymtable 
open Univ

let val_of_constr env c =
  val_of_constr (pre_env env) c

(* Test la structure des piles *)

let compare_zipper z1 z2 =
  match z1, z2 with
  | Zapp args1, Zapp args2 -> nargs args1 = nargs args2
  | Zfix _, Zfix _ -> true 
  | Zswitch _, Zswitch _ -> true
  | _ , _ -> false

let rec compare_stack stk1 stk2 =
  match stk1, stk2 with
  | [], [] -> true
  | z1::stk1, z2::stk2 ->
      if compare_zipper z1 z2 then compare_stack stk1 stk2
      else false
  | _, _ -> false 

(* Conversion *)
let conv_vect fconv vect1 vect2 cu =
  let n = Array.length vect1 in
  if n = Array.length vect2 then
    let rcu = ref cu in
    for i = 0 to n - 1 do
      rcu := fconv vect1.(i) vect2.(i) !rcu
    done;
    !rcu
  else raise NotConvertible

let infos = ref (create_clos_infos betaiotazeta Environ.empty_env)

let rec conv_val pb k v1 v2 cu =
  if v1 == v2 then cu else conv_whd pb k (whd_val v1) (whd_val v2) cu 
    
and conv_whd pb k whd1 whd2 cu =  
  match whd1, whd2 with
  | Vsort s1, Vsort s2 -> sort_cmp pb s1 s2 cu 
  | Vprod p1, Vprod p2 ->
      let cu = conv_val CONV k (dom p1) (dom p2) cu in
      conv_fun pb k (codom p1) (codom p2) cu
  | Vfun f1, Vfun f2 -> conv_fun CONV k f1 f2 cu
  | Vfix f1, Vfix f2 -> conv_fix k f1 f2 cu
  | Vfix_app fa1, Vfix_app fa2 ->
      let f1 = fix fa1 in
      let args1 = args_of_fix fa1 in
      let f2 = fix fa2 in
      let args2 = args_of_fix fa2 in
      conv_arguments k args1 args2 (conv_fix k f1 f2 cu)
  | Vcofix cf1, Vcofix cf2 -> 
      conv_cofix k cf1 cf2 cu
  | Vcofix_app cfa1, Vcofix_app cfa2 ->	
      let cf1 = cofix cfa1 in
      let args1 = args_of_cofix cfa1 in
      let cf2 = cofix cfa2 in
      let args2 = args_of_cofix cfa2 in
      conv_arguments k args1 args2 (conv_cofix k cf1 cf2 cu)
  | Vconstr_const i1, Vconstr_const i2 -> 
      if i1 = i2 then cu else raise NotConvertible 
  | Vconstr_block b1, Vconstr_block b2 ->
      let sz = bsize b1 in
      if btag b1 = btag b2 && sz = bsize b2 then
	let rcu = ref cu in
	for i = 0 to sz - 1 do
	  rcu := conv_val CONV k (bfield b1 i) (bfield b2 i) !rcu
	done;
	!rcu
      else raise NotConvertible
  | Vatom_stk(a1,stk1), Vatom_stk(a2,stk2) -> 
      conv_atom pb k a1 stk1 a2 stk2 cu
  | _, Vatom_stk(Aiddef(_,v),stk) -> 
      conv_whd pb k whd1 (force_whd v stk) cu
  | Vatom_stk(Aiddef(_,v),stk), _ -> 
      conv_whd pb k (force_whd v stk) whd2 cu
  | _, _ -> raise NotConvertible

and conv_atom pb k a1 stk1 a2 stk2 cu =
  match a1, a2 with
  | Aind (kn1,i1), Aind(kn2,i2) ->
      if i1 = i2 && mind_equiv !infos kn1 kn2 && compare_stack stk1 stk2 then
	conv_stack k stk1 stk2 cu
      else raise NotConvertible
  | Aid ik1, Aid ik2 -> 
      if ik1 = ik2 && compare_stack stk1 stk2 then 
	conv_stack k stk1 stk2 cu 
      else raise NotConvertible
  | Aiddef(ik1,v1), Aiddef(ik2,v2) ->
      begin
	try
	  if ik1 = ik2 && compare_stack stk1 stk2 then
	    conv_stack k stk1 stk2 cu 
	  else raise NotConvertible
	with NotConvertible ->
	  if oracle_order ik1 ik2 then             
            conv_whd pb k (whd_stack v1 stk1) (Vatom_stk(a2,stk2)) cu
          else conv_whd pb k (Vatom_stk(a1,stk1)) (whd_stack v2 stk2) cu
      end
  | Aiddef(ik1,v1), _ ->
      conv_whd pb k (force_whd v1 stk1) (Vatom_stk(a2,stk2)) cu
  | _, Aiddef(ik2,v2) ->
      conv_whd pb k (Vatom_stk(a1,stk1)) (force_whd v2 stk2) cu
  | Afix_app _, _ | _, Afix_app _ | Aswitch _, _ | _, Aswitch _ -> 
      Util.anomaly "Vconv.conv_atom : Vm.whd_val doesn't work"
  | _, _ -> raise NotConvertible 
	
and conv_stack k stk1 stk2 cu =
  match stk1, stk2 with
  | [], [] -> cu
  | Zapp args1 :: stk1, Zapp args2 :: stk2 ->
      conv_stack k stk1 stk2 (conv_arguments k args1 args2 cu) 
  | Zfix fa1 :: stk1, Zfix fa2 :: stk2 ->
      let f1 = fix fa1 in
      let args1 = args_of_fix fa1 in
      let f2 = fix fa2 in
      let args2 = args_of_fix fa2 in
      conv_stack k stk1 stk2 
	(conv_arguments k args1 args2 (conv_fix k f1 f2 cu))
  | Zswitch sw1 :: stk1, Zswitch sw2 :: stk2 ->
      if eq_tbl sw1 sw2 then
	let vt1,vt2 = type_of_switch sw1, type_of_switch sw2 in
	let rcu = ref (conv_val CONV k vt1 vt2 cu) in
	let b1, b2 = branch_of_switch k sw1, branch_of_switch k sw2 in
	for i = 0 to Array.length b1 - 1 do
	  rcu := 
	    conv_val CONV (k + fst b1.(i)) 
	      (snd b1.(i)) (snd b2.(i)) !rcu
	done;
	conv_stack k stk1 stk2 !rcu
      else raise NotConvertible
  | _, _ -> raise NotConvertible

and conv_fun pb k f1 f2 cu =
  if f1 == f2 then cu
  else
    let arity,b1,b2 = decompose_vfun2 k f1 f2 in
    conv_val pb (k+arity) b1 b2 cu

and conv_fix k f1 f2 cu =
  if f1 == f2 then cu 
  else
    if check_fix f1 f2 then
      let tf1 = types_of_fix f1 in
      let tf2 = types_of_fix f2 in
      let cu = conv_vect (conv_val CONV k) tf1 tf2 cu in
      let bf1 = bodies_of_fix k f1 in
      let bf2 = bodies_of_fix k f2 in
      conv_vect (conv_fun CONV (k + (fix_ndef f1))) bf1 bf2 cu
    else raise NotConvertible

and conv_cofix k cf1 cf2 cu =
  if cf1 == cf2 then cu
  else
    if check_cofix cf1 cf2 then
      let tcf1 = types_of_cofix cf1 in
      let tcf2 = types_of_cofix cf2 in
      let cu = conv_vect (conv_val CONV k) tcf1 tcf2 cu in
      let bcf1 = bodies_of_cofix k cf1 in
      let bcf2 = bodies_of_cofix k cf2 in
      conv_vect (conv_val CONV (k + (cofix_ndef cf1))) bcf1 bcf2 cu
    else raise NotConvertible

and conv_arguments k args1 args2 cu =
  if args1 == args2 then cu
  else
    let n = nargs args1 in
    if n = nargs args2 then
      let rcu = ref cu in
      for i = 0 to n - 1 do
	rcu := conv_val CONV k (arg args1 i) (arg args2 i) !rcu
      done;
      !rcu
    else raise NotConvertible

let rec conv_eq pb t1 t2 cu =
  if t1 == t2 then cu 
  else
    match kind_of_term t1, kind_of_term t2 with
    | Rel n1, Rel n2 -> 
	if n1 = n2 then cu else raise NotConvertible
    | Meta m1, Meta m2 ->
	if m1 = m2 then cu else raise NotConvertible
    | Var id1, Var id2 -> 
	if id1 = id2 then cu else raise NotConvertible
    | Sort s1, Sort s2 -> sort_cmp pb s1 s2 cu
    | Cast (c1,_,_), _ -> conv_eq pb c1 t2 cu
    | _, Cast (c2,_,_) -> conv_eq pb t1 c2 cu
    | Prod (_,t1,c1), Prod (_,t2,c2) -> 
	conv_eq pb c1 c2 (conv_eq CONV t1 t2 cu)
    | Lambda (_,t1,c1), Lambda (_,t2,c2) -> conv_eq CONV c1 c2 cu
    | LetIn (_,b1,t1,c1), LetIn (_,b2,t2,c2) -> 
	conv_eq pb c1 c2 (conv_eq CONV b1 b2 cu)
    | App (c1,l1), App (c2,l2) ->
	conv_eq_vect l1 l2 (conv_eq CONV c1 c2 cu)
    | Evar (e1,l1), Evar (e2,l2) ->
	if e1 = e2 then conv_eq_vect l1 l2 cu
	else raise NotConvertible
    | Const c1, Const c2 -> 
	if c1 = c2 then cu else raise NotConvertible
    | Ind c1, Ind c2 -> 
	if c1 = c2 then cu else raise NotConvertible
    | Construct c1, Construct c2 -> 
	if c1 = c2 then cu else raise NotConvertible
    | Case (_,p1,c1,bl1), Case (_,p2,c2,bl2) ->
	let pcu = conv_eq CONV p1 p2 cu in
	let ccu = conv_eq CONV c1 c2 pcu in
	conv_eq_vect bl1 bl2 ccu
    | Fix (ln1,(_,tl1,bl1)), Fix (ln2,(_,tl2,bl2)) ->
	if ln1 = ln2 then conv_eq_vect tl1 tl2 (conv_eq_vect bl1 bl2 cu)
	else raise NotConvertible
    | CoFix(ln1,(_,tl1,bl1)), CoFix(ln2,(_,tl2,bl2)) ->	
	if ln1 = ln2 then conv_eq_vect tl1 tl2 (conv_eq_vect bl1 bl2 cu)
	else raise NotConvertible
    | _ -> raise NotConvertible

and conv_eq_vect vt1 vt2 cu =
  let len = Array.length vt1 in
  if len = Array.length vt2 then
    let rcu = ref cu in
    for i = 0 to len-1 do
      rcu := conv_eq CONV vt1.(i) vt2.(i) !rcu
    done; !rcu
  else raise NotConvertible
      
let vconv pb env t1 t2 =
  let cu =
    try conv_eq pb t1 t2 Constraint.empty
    with NotConvertible ->
      infos := create_clos_infos betaiotazeta env;
      let v1 = val_of_constr env t1 in
      let v2 = val_of_constr env t2 in
      let cu = conv_val pb (nb_rel env) v1 v2 Constraint.empty in
      cu
  in cu
    
let _ = Reduction.set_vm_conv vconv

let use_vm = ref false

let set_use_vm b =
  use_vm := b;
  if b then Reduction.set_default_conv vconv
  else Reduction.set_default_conv Reduction.conv_cmp
      
let use_vm _ = !use_vm

(*******************************************)
(* Calcul de la forme normal d'un terme    *)
(*******************************************)

let crazy_type = mkSet 

let decompose_prod env t =
  let (name,dom,codom as res) = destProd (whd_betadeltaiota env t) in
  if name = Anonymous then (Name (id_of_string "x"),dom,codom)
  else res

exception Find_at of int

(* rend le numero du constructeur correspondant au tag [tag],
   [cst] = true si c'est un constructeur constant *)

let invert_tag cst tag reloc_tbl =
  try 
    for j = 0 to Array.length reloc_tbl - 1 do
      let tagj,arity = reloc_tbl.(j) in
      if tag = tagj && (cst && arity = 0 || not(cst || arity = 0)) then
	raise (Find_at j)
      else ()
    done;raise Not_found 
  with Find_at j -> (j+1)   
             (* Argggg, ces constructeurs de ... qui commencent a 1*)

(* Build the substitution that replaces Rels by the appropriate 
  inductives *)
let ind_subst mind mib =
  let ntypes = mib.mind_ntypes in
  let make_Ik k = mkInd (mind,ntypes-k-1) in 
  Util.list_tabulate make_Ik ntypes

(* Instantiate inductives and parameters in constructor type
   in normal form *)
let constructor_instantiate mind mib params ctyp =
  let si = ind_subst mind mib in
  let ctyp1 = substl si ctyp in
  let nparams = Array.length params in
  if nparams = 0 then ctyp1
  else
    let _,ctyp2 = decompose_prod_n nparams ctyp1 in
    let sp = List.rev (Array.to_list params) in substl sp ctyp2
  
let destApplication t =
  try destApp t 
  with _ -> t,[||]

let construct_of_constr_const env tag typ =
  let cind,params = destApplication (whd_betadeltaiota env typ) in
  let ind = destInd cind in
  let (_,mip) = Inductive.lookup_mind_specif env ind in
  let rtbl = mip.mind_reloc_tbl in
  let i = invert_tag true tag rtbl in
  mkApp(mkConstruct(ind,i), params)

let find_rectype typ =
  let cind,args = destApplication typ in
  let ind = destInd cind in
  ind, args

let construct_of_constr_block env tag typ =
  let (mind,_ as ind),allargs = find_rectype (whd_betadeltaiota env typ) in
  let (mib,mip) = Inductive.lookup_mind_specif env ind in
  let nparams = mib.mind_nparams in
  let rtbl = mip.mind_reloc_tbl in
  let i = invert_tag false tag rtbl in
  let params = Array.sub allargs 0 nparams in
  let specif = mip.mind_nf_lc in
  let ctyp = constructor_instantiate mind mib params specif.(i-1) in
  (mkApp(mkConstruct(ind,i), params), ctyp)
  	
let constr_type_of_idkey env idkey =
  match idkey with
  | ConstKey cst ->
      let ty = (lookup_constant cst env).const_type in
      mkConst cst, ty
  | VarKey id -> 
      let (_,_,ty) = lookup_named id env in 
      mkVar id, ty
  | RelKey i -> 
      let n = (nb_rel env - i) in
      let (_,_,ty) = lookup_rel n env in
      mkRel n, lift n ty

let type_of_ind env ind = 
  let specif = Inductive.lookup_mind_specif env ind in
  Inductive.type_of_inductive specif

let build_branches_type (mind,_ as _ind) mib mip params dep p rtbl =
  (* [build_one_branch i cty] construit le type de la ieme branche (commence
     a 0) et les lambda correspondant aux realargs *)
  let build_one_branch i cty =
    let typi = constructor_instantiate mind mib params cty in
    let decl,indapp = Term.decompose_prod typi in
    let ind,cargs = find_rectype indapp in
    let nparams = Array.length params in
    let carity = snd (rtbl.(i)) in
    let crealargs = Array.sub cargs nparams (Array.length cargs - nparams) in
    let codom = 
      let papp = mkApp(p,crealargs) in
      if dep then
	let cstr = ith_constructor_of_inductive ind (i+1) in
        let relargs = Array.init carity (fun i -> mkRel (carity-i)) in
	let dep_cstr = mkApp(mkApp(mkConstruct cstr,params),relargs) in
	mkApp(papp,[|dep_cstr|])
      else papp
    in 
    decl, codom
  in Array.mapi build_one_branch mip.mind_nf_lc

(* La fonction de normalisation *)

let rec nf_val env v t = nf_whd env (whd_val v) t 

and nf_whd env whd typ =
  match whd with
  | Vsort s -> mkSort s
  | Vprod p ->
      let dom = nf_val env (dom p) crazy_type in
      let name = Name (id_of_string "x") in
      let vc = body_of_vfun (nb_rel env) (codom p) in
      let codom = nf_val (push_rel (name,None,dom) env) vc crazy_type in      
      mkProd(name,dom,codom)	  
  | Vfun f -> nf_fun env f typ
  | Vfix f -> nf_fix env f
  | Vfix_app fa ->
      let f = fix fa in
      let vargs = args_of_fix fa in
      let fd = nf_fix env f in
      let (_,i),(_,ta,_) = destFix fd in
      let t = ta.(i) in
      let _, args = nf_args  env vargs t in
      mkApp(fd,args)
  | Vcofix cf -> nf_cofix env cf 
  | Vcofix_app cfa -> 
      let cf = cofix cfa in
      let vargs = args_of_cofix cfa in
      let cfd = nf_cofix env cf in
      let i,(_,ta,_) = destCoFix cfd in
      let t = ta.(i) in
      let _, args = nf_args env vargs t in
      mkApp(cfd,args) 
  | Vconstr_const n -> construct_of_constr_const env n typ
  | Vconstr_block b ->
      let capp,ctyp = construct_of_constr_block env (btag b) typ in
      let args = nf_bargs env b ctyp in
      mkApp(capp,args)
  | Vatom_stk(Aid idkey, stk) ->
      let c,typ = constr_type_of_idkey env idkey in
      nf_stk env c typ stk
  | Vatom_stk(Aiddef(idkey,v), stk) ->
      nf_whd env (whd_stack v stk) typ
  | Vatom_stk(Aind ind, stk) ->
      nf_stk env (mkInd ind) (type_of_ind env ind) stk 
  | Vatom_stk(_,stk) -> assert false

and nf_stk env c t stk  =
  match stk with
  | [] -> c
  | Zapp vargs :: stk ->
      let t, args = nf_args env vargs t in
      nf_stk env (mkApp(c,args)) t stk 
  | Zfix fa :: stk ->   
      let f = fix fa in
      let vargs = args_of_fix fa in
      let fd = nf_fix env f in
      let (_,i),(_,ta,_) = destFix fd in
      let tf = ta.(i) in
      let typ, args = nf_args env vargs tf in
      let _,_,codom = decompose_prod env typ in
      nf_stk env (mkApp(mkApp(fd,args),[|c|])) (subst1 c codom) stk
  | Zswitch sw :: stk -> 
      let (mind,_ as ind),allargs = find_rectype (whd_betadeltaiota env t) in
      let (mib,mip) = Inductive.lookup_mind_specif env ind in
      let nparams = mib.mind_nparams in
      let params,realargs = Util.array_chop nparams allargs in
      (* calcul du predicat du case, 
        [dep] indique si c'est un case dependant *)
      let dep,p = 
	let dep = ref false in
	let rec nf_predicate env v pT =
	  match whd_val v, kind_of_term pT with
	  | Vfun f, Prod _ ->
	      let k = nb_rel env in
	      let vb = body_of_vfun k f in
	      let name,dom,codom = decompose_prod env pT in
	      let body = 
		nf_predicate (push_rel (name,None,dom) env) vb codom in
              mkLambda(name,dom,body)
	  | Vfun f, _ ->
	      dep := true;
	      let k = nb_rel env in
	      let vb = body_of_vfun k f in
	      let name = Name (id_of_string "c") in
	      let n = mip.mind_nrealargs in
	      let rargs = Array.init n (fun i -> mkRel (n-i)) in
	      let dom = mkApp(mkApp(mkInd ind,params),rargs) in
	      let body = 
		nf_val (push_rel (name,None,dom) env) vb crazy_type in
	      mkLambda(name,dom,body)
          | _, _ -> nf_val env v crazy_type
	in 
	let aux = 
	  nf_predicate env (type_of_switch sw) 
	    (hnf_prod_applist env (type_of_ind env ind) (Array.to_list params))
	in
	!dep,aux in
      (* Calcul du type des branches *)
      let btypes = 
	build_branches_type ind mib mip params dep p mip.mind_reloc_tbl in
      (* calcul des branches *)
      let bsw = branch_of_switch (nb_rel env) sw in
      let mkbranch i (n,v) =
	let decl,codom = btypes.(i) in
	let env = 
	  List.fold_right 
	    (fun (name,t) env -> push_rel (name,None,t) env) decl env in
	let b = nf_val env v codom in
	compose_lam decl b 
      in 
      let branchs = Array.mapi mkbranch bsw in
      let tcase = 
	if dep then mkApp(mkApp(p, params), [|c|])
	else mkApp(p, params)
      in
      let ci = case_info sw in
      nf_stk env (mkCase(ci, p, c, branchs)) tcase stk
       
and nf_args env vargs t =
  let t = ref t in
  let len = nargs vargs in
  let targs = 
    Array.init len 
      (fun i ->
	let _,dom,codom = decompose_prod env !t in
	let c = nf_val env (arg vargs i) dom in
	t := subst1 c codom; c) in
  !t,targs

and nf_bargs env b t =
  let t = ref t in
  let len = bsize b in
  let args = Array.create len crazy_type in
  for i = 0 to len - 1 do
    let _,dom,codom = decompose_prod env !t in
    let c = nf_val env (bfield b i) dom in
    args.(i) <- c;
    t := subst1 c codom
  done;
  args
(*  Array.init len 
    (fun i ->
      let _,dom,codom = decompose_prod env !t in
      let c = nf_val env (bfield b i) dom in
      t := subst1 c codom; c) *) 

and nf_fun env f typ =
  let k = nb_rel env in
  let vb = body_of_vfun k f in
  let name,dom,codom = decompose_prod env typ in
  let body = nf_val (push_rel (name,None,dom) env) vb codom in
  mkLambda(name,dom,body)

and nf_fix env f =
  let init = fix_init f in
  let rec_args = rec_args f in
  let ndef = fix_ndef f in
  let vt = types_of_fix f in
  let ft = Array.map (fun v -> nf_val env v crazy_type) vt in
  let name = Array.init ndef (fun _ -> (Name (id_of_string "Ffix"))) in
  let k = nb_rel env in
  let vb = bodies_of_fix k f in 
  let env = push_rec_types (name,ft,ft) env in 
  let fb = Util.array_map2 (fun v t -> nf_fun env v t) vb ft in
  mkFix ((rec_args,init),(name,ft,fb))
  
and nf_cofix env cf =
  let init = cofix_init cf in
  let ndef = cofix_ndef cf in
  let vt = types_of_cofix cf in
  let cft = Array.map (fun v -> nf_val env v crazy_type) vt in
  let name = Array.init ndef (fun _ -> (Name (id_of_string "Fcofix"))) in
  let k = nb_rel env in
  let vb = bodies_of_cofix k cf in 
  let env = push_rec_types (name,cft,cft) env in 
  let cfb = Util.array_map2 (fun v t -> nf_val env v t) vb cft in
  mkCoFix (init,(name,cft,cfb))
  
let cbv_vm env c t  =
  let transp = transp_values () in
  if not transp then set_transp_values true; 
  let v = val_of_constr env c in
  let c = nf_val env v t in
  if not transp then set_transp_values false; 
  c