2016-10-23 3 views
2

Pour coups de pied, j'ai décidé d'écrire ma propre version de map, mais enfin apprendre comment utiliser correctement lazy-seq et l'utiliser pour faire la carte paresseuse:fonction carte personnalisée se comporte bizarrement dans des scénarios paresseux

(defn my-map [f [head & tail]] 
    (lazy-seq 
    (if head 
     (cons (f head) (my-map f tail)) 
     tail))) 

Il fonctionne , mais quand j'ai testé son comportement paresseux contre map, j'ai remarqué quelque chose de différent. J'utilise une fonction helper-carte qui imprime quand un élément est traité:

(defn print-map [description-str f coll mapping-f] 
    (mapping-f 
    (fn [x] 
     (do 
     (print (str description-str ":" x)) 
     (f x))) 
    coll)) 

Lors de l'utilisation de la fonction standard map, les éléments sont traités un à la fois, en alternant entre les fonctions:

(defn -main [] 
    (let [m map 
     coll (into '() (range 10 0 -1)) 
     coll2 (print-map "A" identity coll m) 
     coll3 (print-map "B" identity coll2 m)] 
    (println (doall coll3)))) 

Prints:

A:1 B:1 A:2 B:2 A:3 B:3 A:4 B:4 A:5 B:5 A:6 B:6 A:7 B:7 A:8 B:8 A:9 B:9 A:10 B:10 (1 2 3 4 5 6 7 8 9 10) 

Notez comment chaque numéro est traitée par deux fonctions première avant que le reste des éléments sont vus par chaque fonction.

Mais quand je change m en -main-my-map, l'ordre de traitement change légèrement:

A:1 A:2 B:1 A:3 B:2 A:4 B:3 A:5 B:4 A:6 B:5 A:7 B:6 A:8 B:7 A:9 B:8 A:10 B:9 B:10 (1 2 3 4 5 6 7 8 9 10) 

Maintenant, la première fonction est exécutée deux fois pour démarrer, la deuxième fonction est exécutée deux fois de suite à la fin, et par conséquent, les mappages ne sont plus "synchronisés".

Quel est le problème avec my-map qui provoque cela?

Répondre

4

La destruction que vous faites dans my-map appellera next sur votre séquence paresseuse.

Vous pouvez éviter que ne pas destructing:

(defn my-map [f [x :as xs]] 
    #_(next xs) ;; uncomment to observere similar "broken" behaviour 
    (lazy-seq 
    (if x 
     (cons (f x) (my-map f (rest xs))) 
     (rest xs)))) 

;; You can find out what destructing does with this call: 
(destructure '[[x & r :as xs] numbers]) 

Et next is not as lazy as rest.

+0

Ohh. Je vous remercie. – Carcigenicate