针对Haskell中的列表的点积产品
问题描述:
我试图在Prelude库中仅使用函数的两个数字列表之间实现一个点积。我写了下面的功能:针对Haskell中的列表的点积产品
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
而不是你的堆栈溢出将消失。
+0
我测试了'sum',它工作的很好,即使是有10^8个元素的大型列表。我想这个问题来自于'zipWith'的实现。无论如何,我只是将我的GHC升级到版本7.10.3,并且使用'sum'和'zipWith'的标准版本不再有堆栈溢出 – Alain
列表如何生成?这适用于我的一个简单的'重复1.0'。 –
这里的问题是你如何产生你传递给'dot'的参数。 'dot'本身使用不变的空间。 – Alec
这三个函数中的哪一个是通过递归调用实现的? –