2016-04-09 56 views
0

我想建立一個模塊I與memoization。 I.t類型包含一個真實的複雜內容c,以及一些可變屬性(例如,mutable is_cool)。該模塊提供外與函數來計算和獲取屬性(例如,is_cool),這可能是昂貴的,這就是爲什麼可變屬性用於:是否可以保證記憶的一致性?

(*in i.ml *) 
module Content = struct 
    type t = { i: int; mutable j: int } 
    let is_cool (x: t) : bool = ... 
end 

module I : sig 
    type t 
    val get_c: t -> Content.t 
    val is_cool: t -> bool 
    ... 
end = struct 
    type t = { 
    c : Content.t; 
    mutable is_cool : bool option; 
    mutable property_a : int option } 

    let get_c (x: t) -> Content.t = x.c 

    let is_cool (x: t) : bool = 
    match x.is_cool with 
    | Some r -> r 
    | None -> (* not yet calculated *) 
     let r = Content.is_cool x.c in 
     x.is_cool <- Some r; 
     r 
    end 
    ... 

擔心我有,是如何將模塊代碼I和外部代碼,使得對於整個程序執行過程中任何類型爲I.t的值,其可變屬性總是與其內容c一致。一致意味着「可變屬性應該是None或者是Some v,其中v代表內容的當前屬性」。

例如,下面的代碼很有誘惑力的直接修改屬性深受模塊I.t的簽名禁止:

(* in main.ml *) 
open I 

let test (x: I.t) = 
    x.is_cool <- Some false 

但是,它似乎是不容易的禁止這個代碼,從而改變內容:改善這種

(* in main.ml *) 
let test (x: I.t) (i_new: int) = 
    let c = I.get_c x in 
    let c_new = { c with Content.i = i_new } in 
    let y = { x with c = c_new } in 
    (* now the content and the properties in y are likely to be inconsistent *) 

一種方法是添加set模塊I中,始終在{ x with c = c_new }位置使用set x c_new

(*in i.ml *) 
let set (x: t) (c: Content.t) : t = 
    { c = c; is_cool = None; property_a = None } 

然而,仍然存在問題,例如,

1)它仍然是不可能從寫入{ x with c = c_new }

2)在Content.t易變部件的變形例禁止人們(例如, mutable j: int)也可以讓I.t不一致:

(* in main.ml *) 
let test (x: I.t) (j_new: int) = 
    let c = I.get_c x in 
    c.Content.j <- j_new; 
    (* now the content and the properties in x are likely to be inconsistent *) 

有誰知道任何現有reflexi或解決方案面對這種由記憶造成的不一致?如果我們在「record with」的地方始終使用set,並且不允許Content.t中的可變組件,那麼我們能否保證100%的代碼場景的一致性?

回答

0

嗯,你可以使用私人

您的代碼應該是這樣的:

module type C = sig 
    type t = private { i: int; mutable j: int } 
    val new_c : int -> int -> t 
    val is_cool : t -> bool 
end 
module Content : C = struct 
    type t = { i: int; mutable j: int } 
    let new_c = ... 
    let is_cool (x: t) : bool = ... 
end 

module I : sig 
    type t 
    val new_i : int -> int -> t 
    val get_c: t -> Content.t 
    val is_cool: t -> bool 
    ... 
end = struct 
    type t = { 
    c : Content.t; 
    mutable is_cool : bool option; 
    mutable property_a : int option } 

    let new_i = ... 

    let get_c (x: t) -> Content.t = x.c 

    let is_cool (x: t) : bool = 
    match x.is_cool with 
    | Some r -> r 
    | None -> (* not yet calculated *) 
     let r = Content.is_cool x.c in 
     x.is_cool <- Some r; 
     r 
    end 
    ... 

如果你嘗試寫:

let c = {i = 3; j = 3};; 

它會拒絕你回答:

Error: Cannot create values of the private type Content.t 
相關問題