针对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能够执行必要的优化以避免递归调用的代价。我错过了什么吗?我的执行错误?

+0

列表如何生成?这适用于我的一个简单的'重复1.0'。 –

+0

这里的问题是你如何产生你传递给'dot'的参数。 'dot'本身使用不变的空间。 – Alec

+0

这三个函数中的哪一个是通过递归调用实现的? –

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