2010-11-21 5 views
6

Tôi tò mò muốn hiểu tại sao lỗi này xảy ra và đó là cách tốt nhất để giải quyết nó.Lỗi: Không thể đánh giá một cách an toàn định nghĩa của mô đun được xác định đệ quy

Tôi có một vài tệp types.mltypes.mli xác định loại biến thể value có thể có nhiều loại OCaml khác nhau (float, int, list, map, set, v.v ..).

Vì tôi phải sử dụng std-lib trên loại biến thể này, tôi cần phải cụ thể hóa mô-đun Set thông qua functor để có thể sử dụng bộ loại value bằng cách xác định mô-đun ValueSet.

Các thức .ml tập tin là một cái gì đó như:

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) 

Như bạn có thể thấy tôi đã phải xác định các mô-đun ValueSet từ functor để có thể sử dụng kiểu dữ liệu đó. Vấn đề xảy ra khi tôi muốn sử dụng mô-đun đó bên trong tờ khai của I. Để tôi có được lỗi sau:

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

Tại sao điều này xảy ra? Đó là cách tốt để giải quyết nó? Và chỉ cần biết, là cách tiếp cận của tôi với những gì tôi đang cố gắng làm đúng? Bên cạnh đó nó hoạt động như dự định (tôi có thể sử dụng loại ValueSet với các hoạt động của tôi trong các mô-đun khác, nhưng tôi phải bình luận dòng liên quan trong types.ml để vượt qua giai đoạn biên dịch).

tôi đã cố gắng để loại bỏ tất cả các mã không cần thiết và giảm mã để cần thiết cần thiết để điều tra lỗi này .. nếu nó không enought chỉ cần hỏi :)

EDIT: theo OCaml tham khảo chúng tôi có mà

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.

Đây là tất cả những gì tôi tìm thấy cho đến nay, nhưng tôi không nhận được ý nghĩa chính xác ..

Thank trước

Trả lời

3

Sau khi sửa lỗi rõ ràng, ví dụ của bạn biên dịch (với OCaml 3.10, nhưng tôi nghĩ điều này không thay đổi vì mô-đun đệ quy được giới thiệu trong 3.07). Hy vọng rằng những lời giải thích của tôi bên dưới sẽ giúp bạn tìm thấy những gì, trong số các định nghĩa bạn đã bỏ ra, khiến mã của bạn bị từ chối.

Dưới đây là một số mã ví dụ mà được chấp nhận:

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) 

Ở cấp độ biểu hiện, các mô-đun Value không có sự phụ thuộc vào ValueSet. Do đó trình biên dịch tạo mã để khởi tạo Value trước mã để khởi tạo Value và tất cả đều tốt.

Bây giờ hãy thử nhận xét định nghĩa của f_empty.

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

Bây giờ Value không phụ thuộc vào ValueSet, và ValueSet luôn phụ thuộc vào Valuecompare chức năng. Vì vậy, họ là đệ quy lẫn nhau, và điều kiện "module an toàn" phải áp dụng.

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 .

Ở đây, ValueSet là không an toàn vì ValueSet.empty, và Value là không an toàn vì nil.

Lý do để các “mô-đun an toàn” điều kiện là kỹ thuật thực hiện lựa chọn cho mô-đun đệ quy:

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.

Nếu bạn nhận xét ra tuyên bố nil trong chữ ký của Value, bạn có thể để định nghĩa và khai của f_empty. Đó là vì Value hiện là một mô-đun an toàn: nó chỉ chứa các hàm. Bạn có thể để định nghĩa nil trong quá trình triển khai: việc triển khai Value không phải là một mô-đun an toàn, nhưng chính bản thân nó được thực hiện an toàn.

2

tôi thực sự không t chắc chắn bạn đang sử dụng loại cú pháp nào trong chữ ký cho phép let ... Tôi sẽ cho rằng đó là một sai lầm trong khi giảm mã cho chúng tôi. Bạn cũng không cần định nghĩa OrderedType này, có thể là một lỗi không quan trọng đối với chúng tôi, vì bạn không sử dụng nó trong tham số của mô-đun Set.

Bên cạnh đó, tôi không gặp vấn đề gì khi chạy những điều sau trong trường hợp toplevel. Vì điều này làm việc khá trực tiếp, tôi không chắc chắn làm thế nào bạn nhận được lỗi đó.

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

có, đó là một sai lầm trong khi giảm (đó là một 'loại ... và giá trị =' nhưng tôi loại bỏ các loại khác). Trên thực tế không có sự khác biệt khác, chỉ cần kiểm tra, vì vậy tôi thực sự không biết những gì có thể gây ra lỗi đó. Tôi sẽ kiểm tra nó tốt hơn và cho bạn biết, cảm ơn trong khi đó. – Jack

+0

Ok, tôi đã thử mã đầy đủ của 'types.ml' bên trong toplevel và nó không hoạt động, cho cùng một lỗi' Lỗi: Không thể đánh giá một cách an toàn định nghĩa của mô-đun đệ quy xác định I' .. đó là ngớ ngẩn. Trong khi bạn làm giảm phiên bản làm việc, nhưng nếu tôi bình luận chỉ là dòng đó cũng công trình của tôi .. – Jack

+0

Điều này rất có thể là một vấn đề Gilles định nghĩa; đảm bảo rằng mô-đun được an toàn bằng cách chuyển đổi bất kỳ giá trị không đổi nào thành các hàm đơn vị. – nlucaroni