经常发生从一个值计算属性的代价很高。因此,最好能够在计算后存储该属性。我想知道如何正确编码。
让我们举个例子。假设我们有一个类型整数,并且我们经常需要计算这种类型的值的素因子(让我们假设负整数的素因子是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_1
,pf_2
,pf_3
的所有计算都非常耗时。我想有一个机制来启用在模块中存储素因子,这样只要整数不变,get_prime_factors
的第二次和第三次只读取已存储的内容。
有谁知道如何修改模块I
来实现这一目标?
我们可能需要引用才能使这种机制成为可能(例如,let vr = ref (I.C 100) in ...
)。我可以使用引用。但是,如果保留值(即calculate_prime_factors
)发生变化,我就不知道如何自动触发!vr
。
答案 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
;;
您需要get
和set
访问的可变数据结构。例如,在列表上引用(但您可能更喜欢哈希表):
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
类型(None
和Some _
)。
答案 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