我目前正在通过在线学习你的Haskell书籍的方式,并且已经到了一个章节,作者正在解释一些列表连接可能效率低下:例如
((((a ++ b) ++ c) ++ d) ++ e) ++ f
Run Code Online (Sandbox Code Playgroud)
据说效率低下.作者提出的解决方案是使用定义为的"差异列表"
newtype DiffList a = DiffList {getDiffList :: [a] -> [a] }
instance Monoid (DiffList a) where
mempty = DiffList (\xs -> [] ++ xs)
(DiffList f) `mappend` (DiffList g) = DiffList (\xs -> f (g xs))
Run Code Online (Sandbox Code Playgroud)
我很难理解为什么DiffList在某些情况下比简单串联更具计算效率.有人可以用简单的语言向我解释为什么上面的例子是如此低效,以及DiffList以什么方式解决了这个问题?
有很多很好的问题和答案对foldl,foldr以及foldl'在Haskell.
所以现在我知道:
1)foldl是懒惰的
2)不要使用,foldl因为它可以炸毁堆栈
3)使用foldl'而不是因为它是严格的(ish)
如何foldl评估:
1)创建了一大堆thunks
2)在Haskell完成创建thunk之后,thunk被减少
3)如果有太多的thunk,则溢出堆栈
我对此感到困惑:
1)为什么减少必须在所有thunk之后发生?
2)为什么foldl评估不像foldl'?这只是一个实施副作用吗?
3)从定义看,foldl看起来可以使用尾递归有效地评估 - 我如何判断一个函数是否真的会被有效地评估?如果我不希望我的程序崩溃,似乎我必须开始担心Haskell中的评估顺序.
提前致谢.我不知道我对评估的理解foldl是否正确 - 如有必要,请提出更正建议.
更新:看起来我的问题的答案与Normal Form,Weak Normal Form和Head Normal Form以及Haskell的实现有关.
但是,我仍然在寻找一个例子,更加热切地评估组合函数会导致不同的结果(崩溃或不必要的评估).