2017-10-09 90 views
1

我試圖在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

這三個函數中的哪一個是通過遞歸調用實現的? –

回答

6

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