您好我正在查看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)
根本不会从中受益吗?
答案 0 :(得分:11)
memoized_fib
是CAF,与避免创建新内容的文字常量一样好。没有变量⇒没有东西可以将新东西绑定到⇒没有新东西的创建(简化术语)。
答案 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