2010-11-21 12 views
6

Tengo curiosidad por comprender por qué ocurre este error y cuál es la mejor manera de evitarlo.Error: No se puede evaluar con seguridad la definición del módulo de definición recursiva

que tienen un par de archivos types.ml y types.mli que definen una variante de tipo value que pueden ser de muchos diferentes tipos internos OCaml (float, int, lista, mapa, sistema, etc ..).

Como tengo que usar el std-lib sobre este tipo de variante, necesitaba concretar el módulo Set a través del functor para poder usar conjuntos del tipo value definiendo el módulo ValueSet.

El archivo final .ml es algo así como:

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 i v -> 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) 

Como se puede ver tuviera que definir el módulo ValueSet del funtor que ser capaz de utilizar ese tipo de datos. El problema ocurre cuando quiero usar ese módulo dentro de la declaración de I. Para que obtenga el siguiente error:

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

¿Por qué sucede esto? ¿Cuál es una buena manera de resolverlo? Y solo para saber, ¿mi enfoque de lo que trato de hacer es correcto? Aparte de eso, funciona según lo previsto (puedo usar el tipo ValueSet con mis operaciones en otros módulos, pero tengo que comentar la línea implicada en types.ml para pasar la fase de compilación).

Me trataron de eliminar todo el código superfluos y reducir el código para necesaria esencial investigar este error .. si no es enought simplemente pregunta :)

EDIT: de acuerdo con la referencia OCaml tenemos que

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 typexpr1 -> typexpr2.

Esto es todo lo que he encontrado hasta ahora, pero no consigo el significado exacto ..

Gracias de antemano

Respuesta

3

Después de corregir los errores obvios, su ejemplo se compila (con OCaml 3.10, pero creo que esto no ha cambiado desde que se introdujeron los módulos recursivas en 3,07). Espero que mis explicaciones a continuación te ayuden a encontrar lo que, entre las definiciones que dejaste fuera, hizo que tu código fuera rechazado.

Aquí hay un código de ejemplo que se acepta:

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) 

A nivel de expresión, el módulo Value no tiene dependencia ValueSet. Por lo tanto, el compilador genera el código para inicializar Value antes del código para inicializar Value, y todo va bien.

Ahora intente comentando la definición de f_empty.

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

Ahora Value no depende de ValueSet y ValueSet siempre depende de Value debido a la función compare. Por lo tanto, son mutuamente recursivas y debe aplicarse la condición de "módulo seguro".

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 .

Aquí, ValueSet no es seguro debido a ValueSet.empty y Value no es seguro debido a nil.

La razón a la condición de “módulo de seguridad” es la técnica de aplicación elegido para el módulo recursivo:

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.

Si comente la declaración de nil en la firma de Value, puede dejar la definición y la declaración de f_empty. Eso es porque Value ahora es un módulo seguro: contiene solo funciones. Está bien dejar la definición de nil en la implementación: la implementación de Value no es un módulo seguro, pero el propio Value (que es su implementación forzada a una firma) es seguro.

2

estoy realmente no hay Asegúrese de qué tipo de sintaxis está utilizando en la firma que permite let ... Voy a suponer que fue un error al reducir el código para nosotros. Tampoco necesita esa definición OrderedType, posiblemente otro error de viñetas para nosotros, ya que no lo usa en la parametrización del módulo Set.

Aparte de eso, no tengo problemas para ejecutar lo siguiente en el toplevel. Dado que esto funciona bastante directamente, no estoy seguro de cómo está obteniendo ese 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) 
+0

sí, fue un error al reducir (era un 'tipo ... y valor =' pero eliminé otros tipos). En realidad, no hay otras diferencias, simplemente comprobadas, así que realmente no sé qué puede estar causando ese error. Lo revisaré mejor y le haré saber, gracias mientras tanto. – Jack

+0

Ok, probé el código completo de 'types.ml' dentro del toplevel y no funciona, dando el mismo error' Error: No se puede evaluar con seguridad la definición del módulo I recursivamente definido. Eso es una tontería. Mientras que la versión reducida funciona, pero si comento exactamente esa línea, también funciona la mía. – Jack

+0

Probablemente este sea un problema que Gilles define; asegúrese de que el módulo esté seguro convirtiendo cualquier valor constante en funciones de la unidad. – nlucaroni

Cuestiones relacionadas