2016-10-23 12 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) 

注意每個數字是如何通過元件的其餘部分是由任一函數看到第一前兩個功能處理。

但是,當我在-main改變mmy-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