Error: cannot safely evaluate the definition of a recursively-defined module

I am curious to understand why this error occurs, and this is the best way to get around it.

I have several types.ml and types.mli files that determine the type of the value variant, which can have many different built-in OCaml types (float, int, list, map, set, etc.).

Since I should use std-lib over this option, I needed to instantiate the Set module through a functor in order to be able to use sets of type value , defining the ValueSet module.

The final .ml file looks something like this:

 module rec I : sig type value = Nil | Int of int | Float of float | Complex of Complex.t | String of string | List of (value list) ref | Array of value array | Map of (value, value) Hashtbl.t | Set of ValueSet.t ref | Stack of value Stack.t ... type t = value val compare : t -> t -> int end = struct (* same variant type *) and string_value v = match v with (* other cases *) | Set l -> sprintf "{%s} : set" (ValueSet.fold (fun iv -> v^(string_value i)^" ") !l "") end and OrderedValue : sig type t = I.value val compare : t -> t -> int end = struct type t = I.value let compare = Pervasives.compare end and ValueSet : Set.S with type elt = I.value = Set.Make(I) 

As you can see, I needed to define a ValueSet module from a functor in order to be able to use this data type. The problem occurs when I want to use this module inside declaration I So I get the following error:

Error: cannot safely evaluate the definition of a recursively-defined module I

Why is this happening? Is this a good way to solve this problem? And just know my approach to what I'm trying to do right? In addition, it works as intended (I can use the ValueSet type with my operations in other modules, but I have to comment on the involved string in types.ml in order to pass the compilation phase).

I tried to remove all the excess code and reduce the code to the necessary to investigate this error .. if this is not enough, just ask :)

EDIT: according to the OCaml link, we have that

Currently, the compiler requires that all dependency cycles between recursively defined module identifiers go through at least one “safe” module. A module is “safe” if all the definitions of values ​​contained in it have function types typexpr1 → typexpr2.

That is all I have found so far, but I do not understand the exact meaning.

thanks in advance

+6
module ocaml
source share
2 answers

After fixing the obvious errors, your example compiles (with OCaml 3.10, but I think this has not changed since the recursive modules were introduced in 3.07). Hopefully my explanation below will help you find out which of the definitions you left out caused your code to be rejected.

Here is an example of the code that is accepted:

 module rec Value : sig type t = Nil | Set of ValueSet.t val compare : t -> t -> int val nil : t (*val f_empty : unit -> t*) end = struct type t = Nil | Set of ValueSet.t let compare = Pervasives.compare let nil = Nil (*let f_empty () = Set ValueSet.empty*) end and ValueSet : Set.S with type elt = Value.t = Set.Make(Value) 

At the expression level, the Value module is independent of the ValueSet . Therefore, the compiler generates code to initialize the Value before initializing the Value code, and everything is going well.

Now try to comment on the definition of f_empty .

File "simple.ml", line 11, characters 2-200:
Cannot safely evaluate the definition of the recursively-defined module Value

Now Value depends on ValueSet , and ValueSet always depends on Value because of compare function. Therefore, they are mutually recursive, and the condition "safe module" should be applied.

Currently, the compiler requires that all dependency cycles between recursively defined module identifiers go through at least one “safe” module. a module is “safe” if all value definitions contained in it have function types typexpr_1 -> typexpr_2 .

Here, ValueSet unsafe due to ValueSet.empty , and Value unsafe due to nil .

The reason for the “safe module” condition is the selected implementation method for the recursive module:

The evaluation of the definition of a recursive module continues by creating initial values ​​for the involved safe modules, binding all (functional) values ​​to fun _ -> raise Undefined_recursive_module . The defining module expression is then computed, and the initial values ​​for safe modules are replaced by the values ​​computed in this way.

If you comment out the nil declaration in a signature of Value , you can leave the definition and declaration of f_empty . This is because Value now a secure module: it contains only functions. Willingly to leave the definition of nil in the implementation: the Value implementation is not a safe module, but the Value itself (which is its implementation, forced to the signature) is safe.

+3
source share

I really don't know what syntax you use in the signature that let .. allows. I am going to assume that it was a mistake, while reducing code for us. You also do not need the definition of OrderedType , perhaps another mistake for us, since you do not use it when parameterizing the Set module.

In addition, I have no problem running the next one at the top level. Since this works pretty straight forward, I'm not sure how you get this error.

 module rec Value : sig type t = | Nil | Int of int | Float of float | String of string | Set of ValueSet.t val compare : t -> t -> int val to_string : t -> string end = struct type t = | Nil | Int of int | Float of float | String of string | Set of ValueSet.t let compare = Pervasives.compare let rec to_string = function | Nil -> "" | Int x -> string_of_int x | Float x -> string_of_float x | String x -> x | Set l -> Printf.sprintf "{%s} : set" (ValueSet.fold (fun iv -> v^(to_string i)^" ") l "") end and ValueSet : Set.S with type elt = Value.t = Set.Make (Value) 
+2
source share

All Articles