OCaml中的记忆和参考列表

时间:2016-04-14 16:07:46

标签: recursion functional-programming ocaml

我正在学习OCaml。我知道OCaml为我们提供了强制性的编程风格和函数式编程。

我在计算OCaml中第n个Fibonacci数的课程中遇到了这段代码

let memoise f =
  let table = ref []
  in
  let rec find tab n =
    match tab with
    | []           -> 
            let v = (f n)
            in
            table := (n, v) :: !table;
            v
    | (n', v) :: t -> 
            if n' = n then v else (find t n)
  in
  fun n -> find !table n

let fibonacci2 = memoise fibonacci1

函数fibonacci1以标准方式实现如下:

let rec fibonacci1 n =
  match n with
  | 0 | 1 -> 1
  |     _ -> (fibonacci1 (n - 1)) + (fibonacci1 (n - 2))

现在我的问题是我们如何在fibonacci2中实现备忘录。 {(1}}已在函数fibonacci2中定义,因此,我的逻辑规定在函数完成计算后,列表table应该丢失,并且在每次调用之后,表将一次又一次地构建。

我运行了一个简单的测试,我在OCaml REPL中调用函数table两次,第二个函数调用返回的答案明显快于第一次调用函数(与我的期望相反)。

我认为,如果使用fibonacci 35声明变量,默认情况下可以使用全局范围。

所以我试过这个

ref

但这给了我一个错误,说x的值是无限的。

为什么这样做?

1 个答案:

答案 0 :(得分:3)

函数memoise返回一个值,称之为f。 (f恰好是一个函数)。该值的一部分是表格。每次拨打memoise时,您都会获得不同的值(使用不同的表格)。

在示例中,返回值f的名称为fibonacci2。所以,名为fibonacci2的东西里面有一个表,可以被函数f使用。

默认情况下没有全局范围,这将是一个巨大的混乱。无论如何,这是一个终身而非范围的问题。只要能以某种方式到达对象,OCaml的生命周期就会持续。对于表格,可以通过返回的函数到达它,因此只要函数有效,它就会持续。

在第二个示例中,您正在测试x的范围(而不是生命周期),实际上x的范围仅限于其let的子表达式。 (即,它仅在表达式y中有意义,它不使用它。)在原始代码中,table的所有用法都在其let内,因此没有问题。

尽管引用有点棘手,但OCaml的基本语义来自lambda演算,并且非常干净。这就是为什么在OCaml(恕我直言)中编码是如此令人高兴。