当应用于斐波那契数列时,ocaml回忆录失败

当应用于斐波那契数列时,ocaml回忆录失败,ocaml,Ocaml,我尝试使用记忆技术来优化斐波那契的计算。我的代码是: let memo f = let vtable = ref [] in let rec match_function x vt= match vt with |(x',y)::_ when x=x' -> y |_::l -> match_function x l |[] -> let y = (f x) in vtable

我尝试使用记忆技术来优化斐波那契的计算。我的代码是:

let memo f = 
  let vtable = ref [] in
  let rec match_function x vt=
    match vt with
      |(x',y)::_ when x=x' -> y
      |_::l ->
        match_function x l
      |[] ->
        let y = (f x) in
        vtable :=  (x,y):: !vtable;
        y 
  in
  (fun x -> (match_function x !vtable));;

let rec ggfib = function
  0|1 as i -> i
  |x -> ggfib(x-1) + ggfib(x-2);;

let memoggfib = memo ggfib;;

let running_time f x =
  let start_time = Sys.time () in
  let y = f x in
  let finish_time = Sys.time() in
  Printf.printf "Time lapse:%f\n"  (finish_time -. start_time);
  y;;


running_time ggfib 30;;
running_time memoggfib 30;;
输出为:

Time lapse:0.357187
Time lapse:0.353663
差别不大。。为什么?更糟糕的是,当我试图用

running_time ggfib 40;;
running_time memoggfib 40;;
程序似乎进入无限循环并停止输出

这里怎么了?什么问题我没有解决

我修改了上面的代码,引入了一个用于记忆的“静态”vtable

let rec ggfib = function
  0|1 as i -> i
  |x -> ggfib(x-1) + ggfib(x-2);;

let running_time x0 =
  let vtable = ref [] in
  let start_time = Sys.time () in
  let x = ref 1 in
  let rec match_function ff x vt=
    match vt with
      |(x',y)::_ when x=x' -> y
      |_::l ->
        match_function ff x l
      |[] ->
        let y = (ff x) in
        vtable :=  (x,y):: !vtable;
        y 
  in
  let y=ref 1 in
  while !x<x0 do
    y:= match_function ggfib !x !vtable;
    x:=!x+1;
  done;
  let finish_time = Sys.time() in
  Printf.printf "Time lapse:%f\n"  (finish_time -. start_time);
  y;;


let running_time2 x0=
  let start_time = Sys.time () in
  let x = ref 1 in
  while !x<x0 do
  ggfib !x;
  x:=!x+1;
  done;
  let finish_time = Sys.time() in
  Printf.printf "Time lapse:%f\n"  (finish_time -. start_time);;

running_time 40;;
running_time2 30;;

在我看来,你只是在记最外面的电话。内部调用是到ggfib,而不是到(memo ggfib)

调用memoggfib时,memo函数将记住最外层调用的值。但是,内部调用由ggfib(传递给memo的函数)处理。如果你看一下ggfib的定义,你会发现它调用自己。它不呼叫(备忘录ggfib)

我看不到一种将普通(递归)函数转换为记忆函数的方法。它不会在内部自动调用自己的记忆版本


如果你从一个要记忆的函数开始,我仍然会看到“打结”的问题。

对不起,我不明白。你能把它扩展一点吗?@lkahtz:问题是
ggfib
调用
ggfib
,而不是
memo ggfib
。这意味着您对
memoggfib
的调用将执行一次检查,以查看以前是否使用该参数调用过它,然后调用
ggfib
;它多次调用
ggfib
。非常感谢!!!请允许我考虑一下你的帖子。对于一个新的学习者来说,有很多东西需要咀嚼。
Time lapse:0.581918
Time lapse:0.577813
(* a "derecursified" version of fibonacci: recursive calls are
  replaced by calls to a function passed as parameter *)
let rec fib_derec f = function
| 0|1 as i -> i
| n -> f (n - 1) + f (n - 2)

(* to get the fibonacci back we need to compute a fixpoint:
   fib_derec should get passed 'fib' as parameter,
   which we will define in term of fib_derec
*)
let rec fib n = fib_derec fib n

let test = Array.init 10 fib
(* [|0; 1; 1; 2; 3; 5; 8; 13; 21; 34|] *)

(* we can make this construction generic *)
let rec fix derec input = derec (fix derec) input

let fib = fix fib_derec

let test = Array.init 10 fib
(* [|0; 1; 1; 2; 3; 5; 8; 13; 21; 34|] *)


(* Trick: we can use this tying-the-knot operator to insert
   memoization "between the recursive calls" of the recursive function *)

let rec memo_fix table derec =
  fun input ->
    try Hashtbl.find table input with Not_found ->
      let result = derec (memo_fix table derec) input in
      Hashtbl.add table input result;
      result

let fib_table = Hashtbl.create 100 
let fib = memo_fix fib_table fib_derec

let test = Array.init 10 fib
(* [|0; 1; 1; 2; 3; 5; 8; 13; 21; 34|] *)

let test2 = fib 1000
(* -591372213: overflow, but quick result *)