在this answer on CodeReview中,提问者和回答者似乎都对(++)运算符表示不屑。这是由于它的速度(导致算法明确地在O(n ^ 2)中运行,其中n是列表的长度iirc)?如果不进行其他测试,这是否是预优化,因为Haskell因难以推断时间复杂性而闻名?其他人是否应该避免程序中的(++)运算符?
答案 0 :(得分:9)
取决于。
考虑表达式
foldl (++) [] list
此表达式将列表列表连接到单个列表中,但具有上述二次复杂度。发生这种情况是因为(++)
的实现遍历整个左侧列表并将每个元素添加到右侧列表中(同时保持正确的顺序)。
使用正确的折叠,我们得到线性复杂性:
foldr (++) [] list
这是由(++)
运算符的实现引起的,它只遍历左参数并将其前置在右边。
[1,2] ++ [3,4] ++ [5,6]
等于
-- Example as created by foldr
[1,2] ++ ([3,4] ++ [5,6])
== [1,2] ++ [3,4,5,6]
== [1,2,3,4,5,6] -- all good, no element traversed more than once
只遍历每个列表元素一次。
现在将括号切换到前两个列表更加昂贵,因为现在一些元素被遍历了多次,效率很低。
-- Example as created by foldl
([1,2] ++ [3,4]) ++ [5,6]
== [1,2,3,4] ++ [5,6]
== [1,2,3,4,5,6] -- the sublist [1,2] was traversed twice due to the ordering of the appends
总而言之,请注意这些情况,你应该没事。