2017-10-09 7 views
1

J'essaie d'implémenter un produit scalaire entre deux listes de nombres en utilisant uniquement des fonctions de la bibliothèque Prelude. J'ai écrit la fonction suivante:Produit scalaire pour les listes dans Haskell

dot :: Num a => [a] -> [a] -> a 
dot x y = sum $ zipWith (*) x y 

que je l'ai testé comme suit:

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() 

Malheureusement, ce code conduit à un dépassement de l'espace de pile pour les listes avec 1 million d'éléments (à l'aide GHC 7.6. 3 et le drapeau d'optimisation -O2).

Pour un cas aussi simple, je m'attendais à ce que ghc puisse effectuer les optimisations nécessaires pour éviter le coût des appels récursifs. Est-ce que je manque quelque chose? Ma mise en œuvre est-elle incorrecte?

+0

Comment les listes sont-elles produites? Cela fonctionne pour moi avec un simple 'repeat 1.0'. –

+0

Le problème ici serait de savoir comment vous produisez les arguments que vous passez à 'dot'. 'dot' lui-même utilise un espace constant. – Alec

+0

Laquelle des trois fonctions est implémentée avec des appels récursifs? –

Répondre

6

sum est (mis en œuvre) avec foldr. C'est un peu un choix bête pour plus instances de Num; un pli gauche strict est préférable. À la place, le débordement de pile disparaîtra.

+0

J'ai aussi testé 'sum', et cela fonctionnait bien, même pour des listes plus grandes avec 10^8 éléments. Je suppose que le problème venait de l'implémentation de 'zipWith'. Quoi qu'il en soit, je viens de mettre à jour mon GHC vers la version 7.10.3 et il n'y a plus de débordement de pile en utilisant les versions standard de 'sum' et' zipWith' – Alain