aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/extraction/common.ml1
-rw-r--r--contrib/extraction/ocaml.ml93
-rw-r--r--contrib/extraction/ocaml.mli2
3 files changed, 66 insertions, 30 deletions
diff --git a/contrib/extraction/common.ml b/contrib/extraction/common.ml
index 80f62eb3c0..5e1d4c8086 100644
--- a/contrib/extraction/common.ml
+++ b/contrib/extraction/common.ml
@@ -199,6 +199,7 @@ let init_global_ids lang =
global_ids := !keywords
let extract_to_file f prm decls =
+ cons_cofix := Refset.empty;
current_module := prm.mod_name;
init_global_ids prm.lang;
let preamble,pp_decl = match prm.lang,prm.mod_name with
diff --git a/contrib/extraction/ocaml.ml b/contrib/extraction/ocaml.ml
index 42cd5a54bc..34af744f77 100644
--- a/contrib/extraction/ocaml.ml
+++ b/contrib/extraction/ocaml.ml
@@ -23,6 +23,8 @@ open Nametab
let current_module = ref None
+let cons_cofix = ref Refset.empty
+
(*s Some utility functions. *)
let rec collapse_type_app = function
@@ -199,27 +201,46 @@ let rec pp_expr par env args =
| MLglob r ->
apply (pp_global r)
| MLcons (r,[]) ->
- pp_global r
+ if Refset.mem r !cons_cofix then
+ (open_par par ++ str "lazy " ++ pp_global r ++ close_par par)
+ else pp_global r
| MLcons (r,[a]) ->
- (open_par par ++ pp_global r ++ spc () ++
+ if Refset.mem r !cons_cofix then
+ (open_par par ++ str "lazy (" ++
+ pp_global r ++ spc () ++
+ pp_expr true env [] a ++ str ")" ++ close_par par)
+ else
+ (open_par par ++ pp_global r ++ spc () ++
pp_expr true env [] a ++ close_par par)
| MLcons (r,args') ->
- (open_par par ++ pp_global r ++ spc () ++
+ if Refset.mem r !cons_cofix then
+ (open_par par ++ str "lazy (" ++ pp_global r ++ spc () ++
+ pp_tuple (pp_expr true env []) args' ++ str ")" ++ close_par par)
+ else
+ (open_par par ++ pp_global r ++ spc () ++
pp_tuple (pp_expr true env []) args' ++ close_par par)
- | MLcase (t,[|x|])->
- apply
- (hov 0 (open_par par' ++ str "let " ++
- pp_one_pat
- (str " =" ++ spc () ++
- pp_expr false env [] t ++ spc () ++ str "in")
+ | MLcase (t,[|(r,_,_) as x|])->
+ let expr = if Refset.mem r !cons_cofix then
+ (str "Lazy.force" ++ spc () ++ pp_expr true env [] t)
+ else
+ (pp_expr false env [] t)
+ in apply
+ (hov 0 (open_par par' ++ str "let " ++
+ pp_one_pat
+ (str " =" ++ spc () ++ expr ++ spc () ++ str "in")
env x ++
close_par par'))
| MLcase (t, pv) ->
- apply
- (open_par par' ++
- v 0 (str "match " ++ pp_expr false env [] t ++ str " with" ++
- fnl () ++ str " " ++ pp_pat env pv) ++
- close_par par')
+ let r,_,_ = pv.(0) in
+ let expr = if Refset.mem r !cons_cofix then
+ (str "Lazy.force" ++ spc () ++ pp_expr true env [] t)
+ else
+ (pp_expr false env [] t)
+ in apply
+ (open_par par' ++
+ v 0 (str "match " ++ expr ++ str " with" ++
+ fnl () ++ str " " ++ pp_pat env pv) ++
+ close_par par')
| MLfix (i,ids,defs) ->
let ids',env' = push_vars (List.rev (Array.to_list ids)) env in
pp_fix par env' (Some i) (Array.of_list (List.rev ids'),defs) args
@@ -280,8 +301,10 @@ and pp_function env f t =
let ktl = array_map_to_list (fun (_,l,t0) -> (List.length l,t0)) pv in
not (List.exists (fun (k,t0) -> Mlutil.occurs (k+1) t0) ktl)
in
+ let is_not_cofix pv = let (r,_,_) = pv.(0) in not (Refset.mem r !cons_cofix)
+ in
match t' with
- | MLcase(MLrel 1,pv) ->
+ | MLcase(MLrel 1,pv) when is_not_cofix pv ->
if is_function pv then
(f ++ pr_binding (List.rev (List.tl bl)) ++
str " = function" ++ fnl () ++
@@ -303,7 +326,7 @@ let pp_ast a = hov 0 (pp_expr false (empty_env ()) [] a)
let pp_parameters l =
(pp_tuple pp_tvar l ++ space_if (l<>[]))
-let pp_one_inductive (pl,name,cl) =
+let pp_one_inductive prefix (pl,name,cl) =
let pp_constructor (id,l) =
(pp_global id ++
match l with
@@ -312,7 +335,7 @@ let pp_one_inductive (pl,name,cl) =
prlist_with_sep
(fun () -> (spc () ++ str "* ")) (pp_type true) l))
in
- (pp_parameters pl ++ pp_type_global name ++ str " =" ++
+ (pp_parameters pl ++ str prefix ++ pp_type_global name ++ str " =" ++
(fnl () ++
v 0 (str " " ++
prlist_with_sep (fun () -> (fnl () ++ str " | "))
@@ -320,26 +343,36 @@ let pp_one_inductive (pl,name,cl) =
let pp_inductive il =
(str "type " ++
- prlist_with_sep (fun () -> (fnl () ++ str "and ")) pp_one_inductive il ++
- fnl ())
+ prlist_with_sep (fun () -> (fnl () ++ str "and ")) (pp_one_inductive "") il ++
+ fnl ())
-(*s Pretty-printing of a declaration. *)
+let pp_coinductive_preamble (pl,name,_) =
+ (pp_parameters pl ++ pp_type_global name ++ str " = " ++
+ pp_parameters pl ++ str "__" ++ pp_type_global name ++ str " Lazy.t")
+
+let pp_coinductive il =
+ (str "type " ++
+ prlist_with_sep (fun () -> (fnl () ++ str "and ")) pp_coinductive_preamble il ++
+ fnl () ++ str "and " ++
+ prlist_with_sep (fun () -> (fnl () ++ str "and ")) (pp_one_inductive "__") il ++
+ fnl ())
+
-let warning_coinductive r =
- warn (hov 0
- (str "You are trying to extract the CoInductive definition" ++ spc () ++
- Printer.pr_global r ++ spc () ++ str "in Ocaml." ++ spc () ++
- str "This is in general NOT a good idea," ++ spc () ++
- str "since Ocaml is not lazy." ++ spc () ++
- str "You should consider using Haskell instead."))
+(*s Pretty-printing of a declaration. *)
let pp_decl = function
| Dtype ([], _) ->
if P.toplevel then hov 0 (str " prop (* Logic inductive *)" ++ fnl ())
else (mt ())
- | Dtype ((_,r,_)::_ as i, cofix) ->
- if cofix && (not P.toplevel) then if_verbose warning_coinductive r;
- hov 0 (pp_inductive i)
+ | Dtype (i, cofix) ->
+ if cofix && (not P.toplevel) then begin
+ List.iter
+ (fun (_,_,l) ->
+ List.iter (fun (r,_) ->
+ cons_cofix := Refset.add r !cons_cofix) l) i;
+ hov 0 (pp_coinductive i)
+ end else
+ hov 0 (pp_inductive i)
| Dabbrev (r, l, t) ->
hov 0 (str "type" ++ spc () ++ pp_parameters l ++
pp_type_global r ++ spc () ++ str "=" ++ spc () ++
diff --git a/contrib/extraction/ocaml.mli b/contrib/extraction/ocaml.mli
index 3c39348367..6cabfb7b7b 100644
--- a/contrib/extraction/ocaml.mli
+++ b/contrib/extraction/ocaml.mli
@@ -15,8 +15,10 @@ open Miniml
open Names
open Term
open Nametab
+open Table
val current_module : identifier option ref
+val cons_cofix : Refset.t ref
val collapse_type_app : ml_type list -> ml_type list