繁体   English   中英

foldr1 和 Haskell 上的无限列表

[英]foldr1 and infinite list on Haskell

在这本精彩的书中阅读有关folds的信息,我有一个关于foldr1和那里提出的head'实现的问题,有问题的代码是:

head' = foldr1 (\x _ -> x)

此代码适用于无限列表,而foldl1不适用。 关于为什么是这个答案的一个很好的视觉解释。

考虑到foldr1使用最后一个元素作为累加器,我不太明白它为什么会起作用。 例如:

foldr1 (\x _ -> x) [1..]

这是因为(我认为)惰性评估,即使foldr从列表的最后一个元素(无限)开始,我假设因为 function 没有使用任何中间结果,只返回第一个元素。

那么,编译器是否足够聪明地知道,因为在 lambda function 内部只使用了x ,只返回列表的第一个元素? 即使它应该从头开始?

相反,做

scanr1 (\x _ -> x) [1..]

将打印无限列表的所有元素而不会结束,我想这是foldr正在做的事情,只是编译器足够聪明,不会评估它并返回头部。

提前致谢。

更新

我找到了一个非常好的答案,可以帮助我更深入地了解 foldr 的工作原理:

https://stackoverflow.com/a/63177677/1612432

foldr1使用最后一个元素作为初始累加器值,但组合 function (\x _ -> x)在其第二个参数中是惰性的。

因此,如果列表非空(更不用说无限),则永远不需要“累加器”值,因此永远不需要。

foldr并不意味着它应该从右边开始,只是操作在右边分组/关联/括号。 如果组合 function 在其第二个参数中是严格的,则确实需要从右侧开始计算,但如果不是 - 则不是。

所以不,这不是关于编译器是否聪明,而是关于 Haskell 要求这一点的惰性语义。 foldr被定义为

foldr g z [x1,x2,...,xn]  =  g x1 (foldr g z [x2,...,xn])

foldr1 g xs  =  foldr g (last xs) (init xs)

就是这样。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM