我正在尝试仅使用Prelude库中的函数在两个数字列表之间实现点积。我编写了以下函数:
dot :: Num a => [a] -> [a] -> a
dot x y = sum $ zipWith (*) x y
我测试如下:
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 ()
不幸的是,此代码会导致包含 100 万个元素的列表的堆栈空间溢出(使用 ghc 7.6.3 和优化标志 -O2)。
对于这样一个简单的情况,我本来希望ghc能够执行必要的优化,以避免递归调用的成本。我错过了什么吗?我的实现有误吗?
sum
(过去)是用foldr
实现的。对于大多数Num
实例来说,这是一个有点愚蠢的选择;严格的左折更好。用
import Data.List
sum' :: Num a => [a] -> a
sum' = foldl' (+) 0
相反,您的堆栈溢出将消失。