2016-04-09 11 views
0

私はmemoizationでモジュールIを作りたいと思っています。タイプ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 *) 

一つの方法は、モジュールIsetを追加し、常に{ 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を知っていますこの問題を解決するにはどうすればよいでしょうか? 「レコード」の場所に常に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