我正在尝试仅使用Prelude库中的函数在两个数字列表之间实现点积.我写了以下函数:
dot :: Num a => [a] -> [a] -> a
dot x y = sum $ zipWith (*) x y
Run Code Online (Sandbox Code Playgroud)
我测试如下:
main :: IO ()
main = do
let n = 10^6
x = (replicate n 2.0) :: [Double]
y = (replicate n 3.0) :: [Double]
print $ dot x y
return ()
Run Code Online (Sandbox Code Playgroud)
不幸的是,这段代码导致了包含100万个元素的列表的堆栈空间溢出(使用ghc 7.6.3和优化标志-O2).
对于这种简单的情况,我希望ghc能够执行必要的优化以避免递归调用的成本.我错过了什么吗?我的实施错了吗?
sum是(以前)实现的foldr.对于大多数情况来说,这是一个愚蠢的选择Num; 严格的左侧折叠更好.使用
import Data.List
sum' :: Num a => [a] -> a
sum' = foldl' (+) 0
Run Code Online (Sandbox Code Playgroud)
相反,你的堆栈溢出将消失.