在左侧折叠中构建列表的最有效方法是什么?

时间:2016-04-18 14:26:26

标签: haskell functional-programming fold

在构建列表时,我通常使用右侧折叠,因为这样我可以使用右关联:运算符,而不会影响结果列表的顺序。在左侧折叠中,我可以使用++,但我知道这将需要在生成列表时重复复制列表,为N元素列表提供O(N ^ 2)操作,这通常是不可接受的

所以,当我必须使用左侧折叠时(在我的具体情况下,这是因为我使用foldlM并且生成的monadic动作必须在左到右执行正确的顺序),除了使用:在折叠中构建列表并反转结果之外,还有更好的协调方法吗?

2 个答案:

答案 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:)有效地附加值,最后将此函数应用于[]以获取列表。