Haskell:为什么这样做 - 一个记忆的例子?

时间:2014-01-05 15:50:04

标签: haskell dynamic-programming lazy-evaluation memoization

您好我正在查看Memoization中的示例:

memoized_fib :: Int -> Integer
memoized_fib = (map fib [0 ..] !!)
    where fib 0 = 0
          fib 1 = 1
          fib n = memoized_fib (n-2) + memoized_fib (n-1)

我只是想知道为什么这甚至可以工作,因为对我而言,如果你打电话给memoized_fib(n-2),那么你正在“创建”一个新的清单并用它做事情,在你从它返回之后,包含部分结果的列表将是到哪里去了?那么memorized_fib(n-1)根本不会从中受益吗?

3 个答案:

答案 0 :(得分:11)

memoized_fibCAF,与避免创建新内容的文字常量一样好。没有变量⇒没有东西可以将新东西绑定到⇒没有新东西的创建(简化术语)。

答案 1 :(得分:7)

我可以解释missno的观察,它可以帮助你理解你所看到的行为。重要的是要了解where条款的含义。

您提供的代码是

memoized_fib = (map fib [0 ..] !!)
    where fib = ...

哪个去了

memoized_fib = let fib = ...
               in \n -> map fib [0 ..] !! n

missingno提供了以下内容,看起来像一个简单的eta扩展,但它不是!

memoized_fib n = map fib [0 ..] !! n
    where fib = ...

desugars to

memoized_fib = \n -> let fib = ...
                     in map fib [0 ..] !! n

在前一种情况下,您可以看到fib结构在memoized_fib的调用之间共享,而在后一种情况下fib每次重建。

答案 2 :(得分:1)

您显示的代码取决于给定编译器的行为。这就像Tom Ellis建议的那样令人沮丧:

memoized_fib = 
    let   fib 0 = 0
          fib 1 = 1
          fib n = memoized_fib (n-2) + memoized_fib (n-1)
    in
       (map fib [0 ..] !!)

无法保证列表map fib [0..]将被重复使用,即“shared”。特别是当你省略类型签名时,就像我一样,将其作为多态定义。

最好明确列出该列表,并为其命名:

memoized_fib n = 
    let   fib 0 = 0
          fib 1 = 1
          fib n = g (n-2) + g (n-1)
          g = (fibs !!)
          fibs = map fib [0 ..]
    in
       g n

这是discussed before