如何在 Haskell 中有效地通过foldr 编写反向操作?
请注意,由于复杂性呈二次方增长,平凡的解决方案
reverse a = foldr (\b c -> c ++ [b] ) [] a
效率不高。如果尝试使用通常的foldl 到foldr 转换(盲目地),但我的尝试
foldr (\b g x -> g ((\x old -> x:old) x b)) id list []
没有按我的预期工作。
Note that the trivial solution
reverse a = foldr (\b c -> c ++ [b] ) [] a
is not very efficient, because of the quadratic growth in complexity. If have tried to use the usual foldl to foldr conversion (blindly), but my attempt
foldr (\b g x -> g ((\x old -> x:old) x b)) id list []
did not work as I expected.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
试试这个:
虽然通常使用
Try this:
Though it's usually really better to write it using foldl':
考虑以下内容:
让我们将其“切割”成碎片:
现在我们有了这堆函数,让我们组合它们:
((.), id)
它是Endo
幺半群,所以对于左折叠,我们只需要
Dual
幺半群。(<>) = (:)
和seed = []
或者简单:
Consider the following:
Let's just "cut" it into pieces:
Now we have this bunch of functions, let's compose them:
((.), id)
it'sEndo
monoid, soFor left fold we need just
Dual
monoid.(<>) = (:)
andseed = []
Or simple:
基本上,您需要将 1:2:3:[] 转换为 (3:).(2:).(1:) 并将其应用于 []。因此:
这里累积的 g 的含义是,它通过将 xs 的反向部分尾部附加到它的参数上来作用于它的参数。
对于 1:2:3:[] 示例,在最后一步中 x 将是 3,g 将是 (2:).(1:)。
Basically, you need to transform 1:2:3:[] into (3:).(2:).(1:) and apply it to []. Thus:
The meaning of the accumulated g here is that it acts on its argument by appending the reversed partial tail of xs to it.
For the 1:2:3:[] example, in the last step x will be 3 and g will be (2:).(1:).
老问题,我知道,但是这种方法有什么非最佳的吗,由于惰性求值,foldr 似乎会更快,并且代码相当简洁:
(++) 明显慢于 (:),这需要FUZxxl 的回答中显示了一些逻辑上的扭曲
old question, I know, but is there anything non-optimal about this approach, it seems like foldr would be faster due to lazy evaluation and the code is fairly concise:
is (++) significantly slower than (:), which requires a few logical twists as shown in FUZxxl's answer
reverse = Foldl(\ ab -> b :a) []
reverse = foldl(\ a b -> b :a) []