Haskell函数中的自引用
我正在学习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)是同一个(未评估)列表的尾
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从头到尾处理元素?(我认为不应该,但我不明白为什么不可以)
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)))))))