2016-04-09 3 views
0

Я хочу, чтобы построить модуль I с memoization. Тип I.t содержит реальное сложное содержимое c и некоторые изменчивые свойства (например, mutable is_cool). Модуль обеспечивает снаружи с функциями, чтобы вычислить и получить свойства (например, is_cool), которые могут быть дорогостоящими, поэтому используются изменяемые свойства:Можно ли гарантировать согласованность memoization?

(*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, и всегда использовать set x c_new на месте { x with c = 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