2010-11-23 59 views
2

我想實現「縮小地圖」功能。也就是說,它應該返回由施加f到第一2項的coll的結果的序列,隨後施加f該搜索結果和在coll第三項的結果,等等如何實現懶惰的「縮小地圖」功能?

(def c [[0 0 0 0] [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1]]) 

(defn- sum-vector [v1 v2] 
    (map + v1 v2)) 

(defn reduce-map [f coll & acc] 
    (if (< (count coll) 2) 
    (if (empty? acc) coll acc) 
    (let [head (apply f (take 2 coll)) 
      tail (drop 2 coll)] 
     (recur f (conj tail head) (conj acc head))))) 

對於例如,調用這個函數是這樣的:

(reduce-map sum-vector c) 

應該返回:

[[1 0 0 0] [1 1 0 0] [1 1 1 0] [1 1 1 1]] 

(實際上,它也許應該返回未修改的第一個項目爲好,更好地模擬map,但後來我可以修復)

權,現在,這是它返回:

((1 1 1 1) (1 1 1 0) (1 1 0 0) (1 0 0 0)) 

我如何「推「在(紐約)seq結束?

如果我代替reduce-maprecur,這是它返回:

(((1 1 1 1) ((1 1 1 0) ((1 1 0 0) ((1 0 0 0)))))) 

是在什麼上面我的代碼recur和真正的遞歸之間的區別?

而且,是否有內置的,或更好的,或更習慣的方法來實現reduce-map

最後,我想輸出序列是懶惰的。我只是將整個東西包裝在lazy-seq

回答

10

這聽起來有點像reductions

至於在seq末尾的「推」:一般seqs沒有「結束」,參見。 (iterate inc 0)

至於在列表的末尾「推」:列表不是爲此設計的。使用矢量。用[]播種您的累加器,而不是nil

至於lazy-seq:使用「true」遞歸而不是recur。這裏舉一個例子:

(defn integer-seq 
    [start] 
    (lazy-seq 
    (cons start (integer-seq (inc start))))) 
+0

那麼*快*。謝謝! – 2010-11-23 10:02:21