简体   繁体   English

foldr1 和 Haskell 上的无限列表

[英]foldr1 and infinite list on Haskell

Reading about folds on this wonderful book I have a question regarding foldr1 and the head' implementation proposed there, the code in question is:在这本精彩的书中阅读有关folds的信息,我有一个关于foldr1和那里提出的head'实现的问题,有问题的代码是:

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

this code works on infinite list, whereas foldl1 don't.此代码适用于无限列表,而foldl1不适用。 A good visual explanation about why is this answer .关于为什么是这个答案的一个很好的视觉解释。

I do not quite understand though why does it work, considering that foldr1 is using the last element as accumulator.考虑到foldr1使用最后一个元素作为累加器,我不太明白它为什么会起作用。 For example:例如:

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

This works because (I Think) lazy evaluation, even though foldr is starting from the last element of the list (which is infinite), I'm assuming because the function is not making use of any intermediate result, just return the first element.这是因为(我认为)惰性评估,即使foldr从列表的最后一个元素(无限)开始,我假设因为 function 没有使用任何中间结果,只返回第一个元素。

So, is the compiler smart enough to know that, because inside of the lambda function only x is being used, just returns the first element of the list?那么,编译器是否足够聪明地知道,因为在 lambda function 内部只使用了x ,只返回列表的第一个元素? even though it should start from the end?即使它应该从头开始?

On the contrary, doing相反,做

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

Will print all elements of the infinite list without ending, which I suppose it's what the foldr is doing, just the compiler is smart enough to not evaluate it and return the head.将打印无限列表的所有元素而不会结束,我想这是foldr正在做的事情,只是编译器足够聪明,不会评估它并返回头部。

Thanks in advance.提前致谢。

Update更新

I found a really good answer that helped me understand how foldr works more deeply:我找到了一个非常好的答案,可以帮助我更深入地了解 foldr 的工作原理:

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

foldr1 is using the last element as an initial accumulator value, but the combining function (\x _ -> x) is lazy in its second argument. foldr1使用最后一个元素作为初始累加器值,但组合 function (\x _ -> x)在其第二个参数中是惰性的。

So provided the list is non-empty (let alone infinite), the "accumulator" value is never needed, thus never demanded.因此,如果列表非空(更不用说无限),则永远不需要“累加器”值,因此永远不需要。

foldr does not mean it should start from the right, just that the operations are grouped / associated / parenthesized on the right. foldr并不意味着它应该从右边开始,只是操作在右边分组/关联/括号。 If the combining function is strict in its 2nd argument that will entail indeed starting the calculations from the right, but if not -- then not.如果组合 function 在其第二个参数中是严格的,则确实需要从右侧开始计算,但如果不是 - 则不是。

So no, this is not about compiler being smart, this is about Haskell's lazy semantics that demand this.所以不,这不是关于编译器是否聪明,而是关于 Haskell 要求这一点的惰性语义。 foldr is defined so that foldr被定义为

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

and

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

and that's that.就是这样。

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

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