【发布时间】:2018-05-14 09:28:23
【问题描述】:
考虑将列表连接实现为向左折叠,即foldl (++) []。
在诸如 Haskell 之类的惰性求值语言中,这种实现的复杂性是什么?
我知道,在严格的语言中,性能是元素总数的二次方,但是当涉及惰性时会发生什么?
我尝试手动评估表达式([1,2,3] ++ [4,5,6]) ++ [7,8,9](对应于foldl (++) [] [[1,2,3], [4,5,6], [7,8,9]])
而且似乎我们每个元素只遍历一次,但我不确定我的推理是否正确:
([1,2,3] ++ [4,5,6]) ++ [7,8,9]
= { rewrite expression in prefix notation }
(++) ((++) [1,2,3] [4,5,6]) [7,8,9]
= { the first (++) operation needs to pattern match on its first argument; so it evaluates the first argument, which pattern matches on [1,2,3] }
(++) (case [1,2,3] of {[] -> [4,5,6]; x:xs' -> x:(++) xs' [4,5,6]}) [7,8,9]
= { x = 1, xs' = [2,3] }
(++) (1:(++) [2,3] [4,5,6]) [7,8,9]
= { the first (++) operation can now pattern match on its first argument }
1:([2,3] ++ [4,5,6]) ++ [7,8,9]
我假设(++) 的实现如下:
(++) :: [a] -> [a] -> [a]
xs ++ ys = case xs of [] -> ys
(x:xs') -> x : (xs' ++ ys)
【问题讨论】:
-
也许How is foldl lazy?回答了你的问题具体来说
foldl因为懒惰对性能有影响。 -
对比softwareengineering.stackexchange.com/q/294658/11732:如果你不坚持先形成列表然后扫描它,你只需支付一次连接价格。
标签: performance list haskell time-complexity lazy-evaluation