在构建列表时,我通常使用右侧折叠,因为这样我可以使用右关联:
运算符,而不会影响结果列表的顺序。在左侧折叠中,我可以使用++
,但我知道这将需要在生成列表时重复复制列表,为N元素列表提供O(N ^ 2)操作,这通常是不可接受的
所以,当我必须使用左侧折叠时(在我的具体情况下,这是因为我使用foldlM
并且生成的monadic动作必须在左到右执行正确的顺序),除了使用:
在折叠中构建列表并反转结果之外,还有更好的协调方法吗?
答案 0 :(得分:6)
当我必须使用左折(...因为...产生的monadic动作必须按从左到右的顺序执行)
右侧折叠可以向右倾斜,然后再次向左移动。例如,您可以使用右侧折叠打印(即monadic动作)每个数字并从从左到右计算列表的部分总和:
fun :: [Int] -> IO [Int]
fun xs = foldr go (const $ return []) xs 0
where go x f a = let a' = a + x in print x >> (a' :) <$> f a'
然后:
\> fun [1..5]
1
2
3
4
5
[1,3,6,10,15]
请注意,输出列表是使用(a' :)
构建的,并且monadic操作是从左到右执行的,即使它是正确的折叠。
答案 1 :(得分:3)
由于您提到foldlM
,我的博文可能会深入回答您的问题:
Constructing a list in a Monad
底线是:使用差异列表;即,在左侧,您会累积[a] -> [a]
类型的值,您可以使用. (x:)
有效地附加值,最后将此函数应用于[]
以获取列表。