Haskell函数中的自引用

Haskell函数中的自引用,haskell,recursion,lazy-evaluation,self-reference,Haskell,Recursion,Lazy Evaluation,Self Reference,我正在学习Haskell和我的下列表达 我真的很困惑: fibs = 0 : 1 : zipWith (+) fibs (tail fibs) 我不太明白为什么会这样 如果我应用标准的Currying逻辑(zipWith(+))返回一个函数,将list作为参数,然后返回另一个函数,该函数将另一个list作为参数,并返回一个list(zipWith::(a->b->c)->[a]->[b]->[c])。因此,fibs是对一个列表(尚未评估)的引用,(tail fibs)是同一个(未评估)列表的尾

我正在学习Haskell和我的下列表达 我真的很困惑:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
我不太明白为什么会这样

如果我应用标准的Currying逻辑
(zipWith(+))
返回一个函数,将list作为参数,然后返回另一个函数,该函数将另一个list作为参数,并返回一个list(
zipWith::(a->b->c)->[a]->[b]->[c]
)。因此,
fibs
是对一个列表(尚未评估)的引用,
(tail fibs)
是同一个(未评估)列表的尾部。当我们尝试计算(
取10个fib
)时,前两个元素绑定到
0
1
。换句话说,
fibs==[0,1,,?…]
(尾部fibs)=[1,,?,?]
。第一次添加完成后,
fibs
变为
[0,1,0+1,?,…]
。同样,在第二次加法之后,我们得到
[0,1,0+1,1+(0+1),?,?…]

  • 我的逻辑正确吗
  • 有没有更简单的方法来解释这一点?(了解Haskell complier如何处理此代码的人员有何见解?)(欢迎链接和参考)
  • 确实,这种类型的代码只会因为延迟计算而起作用
  • 当我说谎时会发生什么!!4
  • 这段代码是否假设zipWith从头到尾处理元素?(我认为不应该,但我不明白为什么不可以)
伊迪丝2:我刚找到上面的问题,回答得很好。如果我浪费了任何人的时间,我很抱歉

编辑:这里有一个更难理解的案例(来源:):

filteraport::(a->Bool)->[a]->[a]
filteraport p(x:xs)=如果px那么x:filteraport pxs else[]
main::Int
main=primelist!!10000

其中primelist=2:3:5:[x | x`mod`y/=0)(filteraPort(x mod y/=0).
这里引用x怎么能不引起无限递归?

我将为您跟踪计算:

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

因此:

因此,如果你索引到这个结构中,它将强制对FIB的每一步进行评估,直到找到索引为止

为什么这样有效?一个词:分享

当计算
fibs
时,它会在堆中增长,记录已在计算机中使用的值。稍后返回对
fibs
的引用,以重新使用所有先前计算的
fibs
值。免费记忆

堆中的共享看起来像什么

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


这一结果的终止主要取决于懒惰。

谢谢你,唐。我还不清楚哈斯凯尔是如何知道为了获得下一个元素,它需要称之为谎言的,以及“称之为谎言”是什么意思如果fibs真的是一个列表。我环顾四周,发现了一个,但我仍然不确定列表中的“1”节点和Haskell编译器中的“fibs…”节点之间有什么区别。你可以将
fibs
看作只是一个指针。因此每次你引用
fibs
时,它都会查找值。该值恰好是一个列表。啊!这是一个good point.我应该纠正我的问题。符号
0:1:zipWith…
产生了什么?它开始是一个列表,我理解。但是它到达了列表中的一个节点,这是一个函数调用?或者最好将列表中的所有节点都看作函数调用?例如说
ident x=x
,所以
fib=(ident 0):(ident 1):(zipWith…
.I本例编译器计算所有单元格,但最后一个单元格作为函数调用结束,返回列表?和
(zipWith…)
恰好指向
fibs
列表。对吗?因为我不是专家,所以简化了:Haskell中的每个非严格值都存储在一个名为thunk的结构中。它包含一个值或某种指向可以计算值的代码的指针。因此,当您有
0:1:zipWith
时,第三个元素是指向代码的thunk可以计算列表的其余部分。当代码运行时,thunk被一个cons单元格替换,该单元格具有列表第3个元素的值,以及一个可以从第4位计算列表其余部分的thunk。以此类推。谢谢,David。您正确理解了thunk的概念,这一点非常重要。阅读了第一个示例对我来说是有意义的。人们真的需要了解(编译器)下发生了什么至少从概念上讲,它涵盖了编写好的代码。这似乎是对的。对我来说也很简单——当你与Haskell more合作时,你的大脑会开始学习这些模式,对你来说也会很简单。良好的开端。首先,
Filterableport
takeWhile
相同。其次,你可以通过wr避免偶数第三,如果你使用
[5,7..]
,那么你的初始列表中就没有必要有
5
。最后,这是一个相当深刻的原因。这是因为对于每个素数
p
p^2
之前都有另一个素数。这是林德曼定理(p和2p之间的素数)的一个微不足道的结果谢谢,奥古斯都。你建议的优化和清理是有意义的。至于终止,你能详细说明一下吗?在
(\y->x mod y/=0)
中,
x
绑定到什么?我怀疑我的错误是认为它绑定到一个无限列表。如果它只绑定到一个值(比如,
7
)那么就没有问题了。你能确认吗?
x
绑定到一个元素,来自无限列表
[7..]
。这里没有递归。
> 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)))))))