【发布时间】:2019-07-18 09:13:02
【问题描述】:
我决定认真对待 Haskell,并开始考虑使用 foldl 和 foldr。它们真的很像 Clojure 的 reduce - 但我可能错了,很快就遇到了问题,我希望有人能轻松解释一下。
使用此文档: https://wiki.haskell.org/Foldr_Foldl_Foldl'
在深入实施我自己的 foldr/foldl 版本之前,我决定先测试 Prelude 中的现有版本:
± |master U:2 ✗| → ghci
GHCi, version 8.6.3: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /Users/akarpov/.ghc/ghci.conf
Prelude> foldr (+) 0 [1..9999999]
49999995000000
Prelude> foldr (+) 0 [1..99999999]
*** Exception: stack overflow
没看到(使用 foldl 时结果相同);我宁愿期待一些类似于 Clojure 的东西:
> (time (reduce +' (range 1 99999999)))
"Elapsed time: 3435.638258 msecs"
4999999850000001
唯一明显(且不相关)的区别是使用 +' 而不是 +,但这只是为了适应 JVM 的类型系统 - 生成的数字不适合 [默认] Long,并且 +' 将自动使用需要时使用 BigInteger。最重要的是,没有堆栈溢出。 因此,这似乎表明 Haskell/Clojure 中的折叠/归约要么实现方式非常不同,要么我对 haskell 实现的使用是错误的。
如果相关,这些是全局项目设置: - 包:[] - 解析器:lts-13.8
【问题讨论】:
-
使用
Data.List.foldl',foldl的严格形式。 -
Haskell 等效于 Clojure 的
(reduce +' (range 1 99999999))是foldl' (+) 0 [1..99999998](原文如此)(显然;得到与您显示的相同的结果)。 Haskell 范围包括在内。 -
另见Does Haskell have tail-recursive optimization?。这个问题的措辞不同,但实际上这个问题几乎是重复的——
foldl是尾递归的,等等。
标签: haskell clojure stack-overflow reduce fold