2016-10-23 4 views
2

Для пинков, я решил написать свою собственную версию map, но, наконец, узнать, как правильно использовать lazy-seq и использовать его, чтобы сделать карту ленивой:Пользовательские функции карты ведет себя странно в ленивом сценарии

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

Он работает , но когда я протестировал его ленивое поведение против map, я заметил что-то другое. Я использую функцию хелпер-карту, которая печатает, когда элемент обрабатывается:

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

Когда я использовать стандартную функцию map, элементы обрабатываются по одному за раз, чередуя между функциями:

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

Печать:

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) 

Обратите внимание, как каждое число обрабатывается обеих функций, прежде чем остальные элементы видны либо функции.

Но когда я изменяю m в -main на my-map, порядок обработки изменяется незначительно:

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) 

Теперь первая функция выполняется дважды, чтобы начать, то вторая функция работает в два раза подряд, в конце концов, и как следствие, сопоставления больше не «синхронизированы».

Что случилось с my-map, что заставляет это случиться?

ответ

4

Уничтожение в my-map будет называть next вашей ленивой очередью.

Вы можете избежать этого, не разрушающие:

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

И next is not as lazy as rest.

+0

Ох. Спасибо. – Carcigenicate