Error: Cannot safely evaluate the definition of the recursively-defined module

和自甴很熟 提交于 2019-12-05 06:32:28

After fixing the obvious errors, your example does compile (with OCaml 3.10, but I think this hasn't changed since recursive modules were introduced in 3.07). Hopefully my explanations below will help you find what, amongst the definitions you left out, caused your code to be rejected.

Here is some example 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 module Value has no dependency on ValueSet. Therefore the compiler generates the code to initialize Value before the code to initialize Value, and all goes well.

Now try commenting out 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 does depend on ValueSet, and ValueSet always depends on Value because of the compare function. So they are mutually recursive, and the “safe module” condition must apply.

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

Here, ValueSet isn't safe because of ValueSet.empty, and Value isn't safe because of nil.

The reason to the “safe module” condition is the chosen implementation technique for recursive module:

Evaluation of a recursive module definition proceeds by building initial values for the safe modules involved, binding all (functional) values to fun _ -> raise Undefined_recursive_module. The defining module expressions are then evaluated, and the initial values for the safe modules are replaced by the values thus computed.

If you comment out the declaration of nil in the signature of Value, you can leave the definition and declaration of f_empty. That's because Value is now a safe module: it contains only functions. It's ok to leave the definition of nil in the implementation: the implementation of Value is not a safe module, but Value itself (which is its implementation coerced to a signature) is safe.

I'm really not sure what kind of syntax you're using in the signature that allows let ... I'm going to assume it was a mistake while reducing the code for us. You also don't need that OrderedType definition, possibly another fiddling error for us, since you don't use it in parameterisation of the Set module.

Aside from that, I have no problem running the following in the toplevel. Since this works pretty directly, I am unsure how you're getting that 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 i v -> v^(to_string  i)^" ") l "")
    end

and ValueSet : Set.S with type elt = Value.t = Set.Make (Value)
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!