2016-09-21 3 views
2

de la pile Pourquoi ai-je besoin de remplacer map avec mapv dans ce morceau de code pour éviter un débordement de pile:réduire et la carte sur l'accumulateur produit trop-plein

#!/bin/bash lein-exec               


(println (reduce (fn [acc _]              
        ;;(mapv #(inc %) acc))          
        (map #(inc %) acc))           
       (repeat 2 0)             
       (range (long 1e6))))   

~

Je ne comprends pas comment le acc est traité lorsqu'il est paresseux. Merci pour votre avis.

Répondre

4

Fondamentalement, ce que vous obtenez est un grand nombre de séquences imbriquées paresseux, qui, quand a poussé, causer un débordement de pile.

Regardons à plus petit exemple:

(reduce (fn [acc _] 
      (map inc acc)) 
     (repeat 2 0) 
     (range 3)) 

Depuis map est paresseux, le résultat de plus haut sera le prochain:

(map inc (map inc (map inc (0 0))) 

Vous n'êtes pas mappez avec impatience acc avec inc, mais seulement mettre des séquences paresseuses les unes dans les autres, ce qui sera réalisé par la suite.

Pour en revenir à l'exemple d'origine où range prend 1e6, le résultat sera le suivant:

(map inc 
    (map inc 
     (<... rougly 1e6 nested lazy sequences here ...> 
      (map inc (0 0))) ...) 

Se rendant compte de ce consommera environ 1e6 cadres de la pile, ce qui va certainement causer un débordement de pile.

En cas de mapv paresse est pas impliqué et acc se réalise tout de suite, de sorte que le résultat de votre exemple sera [1000000 1000000] juste après reduce finitions.