Haskell函数中的自引用

时间:2011-06-15 23:44:25

标签: haskell recursion lazy-evaluation self-reference

我正在学习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)时,前两个元素绑定到01。换句话说,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不会导致无限递归?

1 个答案:

答案 0 :(得分:15)

我将为您追踪评估:

> fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

使用:

> zipWith f (a:as) (b:bs) = f a b : zipWith f as bs
> zipWith _ _      _      = []

> tail (_:xs)             =  xs
> tail []                 =  error "tail" 

所以:

  fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
↪ fibs = 0 : 1 : ((+) 0 1 : zipWith (+) (tail fibs) (tail (tail fibs)))
↪ fibs = 0 : 1 : 1 : ((+) 1 1 : zipWith (+) (tail (tail fibs)) (taii (tail (tail fibs)))))    
↪ fibs = 0 : 1 : 1 : 2 : ((+) 1 2 : zipWith (+) (tail (tail (tail fibs))) (tail (taii (tail (tail fibs))))))
↪ fibs = 0 : 1 : 1 : 2 : 3 : ((+) 2 3 : zipWith (+) (tail (tail (tail (tail fibs)))) (tail (tail (taii (tail (tail fibs)))))))

等。因此,如果您索引此结构,它将强制评估每个fibs步骤,直到找到索引。

为什么效率这么高?一句话:分享

计算fibs时,它会在堆中增长,记录已经是计算机的值。稍后对fibs的引用将重用fibs的所有先前计算的值。免费记忆!

堆中的共享是什么样的?

enter image description here

当您在列表末尾请求对象时,Haskell计算下一个值,记录它,并将该自引用移动到节点下。

这终止的事实主要取决于懒惰。