【发布时间】:2011-06-15 23:44:25
【问题描述】:
我正在学习 Haskell,我在 Haskell Wiki 上的以下表达式 真的让我很困惑:
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
我不太明白为什么会这样。
如果我应用标准 Currying 逻辑 (zipWith (+)) 返回一个以列表为参数的函数,然后返回另一个以另一个列表作为参数的函数,并返回一个列表 (zipWith::(a -> b -> c) -> [a] -> [b] -> [c])。因此,fibs 是对列表(尚未评估)的引用,(tail fibs) 是同一(未评估)列表的尾部。当我们尝试评估 (take 10 fibs) 时,前两个元素绑定到 0 和 1。换句话说,fibs==[0,1,?,?...] 和 (tail fibs)==[1,?,?,?]。第一次添加完成后,fibs 变为 [0,1,0+1,?,..]。同样,在第二次加法之后,我们得到[0,1,0+1,1+(0+1),?,?..]
- 我的逻辑正确吗?
- 有没有更简单的方法来解释这个? (知道 Haskell 编译器如何处理此代码的人有什么见解吗?)(欢迎提供链接和参考)
- 这种类型的代码真的是因为惰性求值才有效吗?
- 当我执行
fibs !! 4时会发生什么评估? - 此代码是否假定 zipWith 先到后处理元素? (我认为不应该,但我不明白为什么不)
EDIT2:我刚刚发现上面提出的问题并得到了很好的回答here。如果我浪费了任何人的时间,我很抱歉。
编辑:这是一个更难理解的案例(来源:Project Euler forums):
filterAbort :: (a -> Bool) -> [a] -> [a]
filterAbort p (x:xs) = if p x then x : filterAbort p xs else []
main :: Int
main = primelist !! 10000
where primelist = 2 : 3 : 5 : [ x | x <- [7..], odd x, all (\y -> x `mod` y /= 0) (filterAbort (<= (ceiling (sqrt (fromIntegral x)))) primelist) ]
注意all (\y -> x mod y /= 0)...这里引用x怎么不会导致无限递归?
【问题讨论】:
-
这似乎是对的。这对我来说似乎也很简单——当你更多地使用 Haskell 时,你的大脑会开始接受这些模式,而且对你来说也很简单。好的开始。
-
首先,
filterAbort与takeWhile相同。其次,您可以通过写[7,9..]来避免偶数。第三,如果您使用[5,7..],则无需在初始列表中包含5。最后,这个工作的原因是相当深刻的。这是因为对于每个素数p在p^2之前还有另一个素数。 Is 是 Lindemann 定理(p 和 2p 之间的素数)的一个微不足道的结果。 -
谢谢,augustss。您建议的优化和清理是有道理的。至于终止,你能详细说明一下吗?
x绑定到(\y -> x mod y /= 0)是什么?我怀疑我的错误在于认为它绑定到一个无限列表。如果它只绑定一个值(例如,7),那么就没有问题。你能确认一下吗? -
x绑定到单个元素,来自无限列表[7..]。这里没有递归。
标签: haskell recursion lazy-evaluation self-reference