带商店的模块

时间:2016-03-11 11:55:48

标签: reference ocaml record

经常发生从一个值计算属性的代价很高。因此,最好能够在计算后存储该属性。我想知道如何正确编码。

让我们举个例子。假设我们有一个类型整数,并且我们经常需要计算这种类型的值的素因子(让我们假设负整数的素因子是None):

module I =
struct
  type t = C of int
  type pf = (int list) option 

  let calculate_prime_factors (x: t) : pf =
    (* a costly function to calculate prime factors *)
    ... ...

  let get_prime_factors (x: t) : pf =
    calculate_prime_factors x
end

let () = 
  let v = I.C 100 in
  let pf_1 = I.get_prime_factors v in
  let pf_2 = I.get_prime_factors v in
  let pf_3 = I.get_prime_factors v in
  ...

目前,get_prime_factors只调用了calculate_prime_factors,因此,pf_1pf_2pf_3的所有计算都非常耗时。我想有一个机制来启用在模块中存储素因子,这样只要整数不变,get_prime_factors的第二次和第三次只读取已存储的内容。

有谁知道如何修改模块I来实现这一目标?

我们可能需要引用才能使这种机制成为可能(例如,let vr = ref (I.C 100) in ...)。我可以使用引用。但是,如果保留值(即calculate_prime_factors)发生变化,我就不知道如何自动触发!vr

3 个答案:

答案 0 :(得分:2)

您要做的是memoization,不是吗?

你可以试试这个:

module I =
  struct

  type t = C of int
  type pf = (int list) option 

  let calculate_prime_factors (x: t) : pf =
    (* a costly function to calculate prime factors *)
    ... ...

  module HI = Hashtbl.Make (struct 
    type t = C of int 
    let equal = (=) 
    let hash (C x) = x
  end)

  let get_prime_factors =
    let h = Hashtbl.create 17 in
    fun x ->
      try Hashtbl.find h x 
    with
      Not_found -> let pf = calculate_prime_factors x in
                   Hashtbl.add h x pf;
                   pf
end

let () = 
  let v = I.C 100 in
  let pf_1 = I.get_prime_factors v in
  let pf_2 = I.get_prime_factors v in
  let pf_3 = I.get_prime_factors v in
  ...

您可以根据负整数对其进行调整(例外情况,例如,这比选项更好),但我希望您明白这一点。

答案 1 :(得分:1)

我会做以下事情:

let get_prime_factors x =
  match get x  with
  | None ->
    let res = calculate_prime_factors x 
    in
    begin
      set x res ;
      res
    end
  | Some res -> res 
;;

您需要getset访问的可变数据结构。例如,在列表上引用(但您可能更喜欢哈希表):

let my_storage = ref [] (* or something mutable *)

let get x = 
  if List.mem_assoc x !my_storage
  then Some (List.assoc x !my_storage)
  else None

let set x r =
  my_storage := (x,r) :: !my_storage ;;

您也可以使用例外代替option类型(NoneSome _)。

答案 2 :(得分:1)

看起来,您正在寻找此解决方案:

module I = struct 
  type t = {
     c : int;
     mutable result : int option;
  }

  let create c = {c; result = None}

  let calculate_prime_factors t = match t.result with
    | Some r -> r
    | None -> 
       let r = do_calculate t.c in
       t.result <- Some r;
       r
end

这称为memoizing。通过Lazy计算,可以更轻松地解决此特定示例。

  module I = struct
    type t = int Lazy.t  
    let create c = lazy (do_calculate c)
    let calculate_prime_factors = Lazy.force
  end