I wrote the next example to trace the inner workings of transducer. I hope that this will help.
The next filter-t(transducer), map-t(transducer) and conj-t(reducer) functions are excerpted from the filter, map and conj from clojure.core and then simplified and modified to focus on the understanding of the inner workings.
(defn filter-t
[pred]
;; The first fn is a transducer. It receives the reducer rf and returns
;; the reducer(the second fn part of this code).
(fn [rf]
(fn
([]
(let [r (rf)]
(println "filter-t [] post: result =" r)
r))
([result]
(println "filter-t [result] pre: result =" result)
(let [r (rf result)]
(println "filter-t [result] post: result =" r)
r))
([result input]
(println "filter-t [result input] pre: result =" result ", input =" input)
(let [r (if (pred input)
(rf result input)
result)]
(println "filter-t [result input] post: result =" r)
r)))))
(defn map-t
[f]
(fn [rf]
(fn
([]
(let [r (rf)]
(println "map-t [] post: result =" r)
r))
([result]
(println "map-t [result] pre: result =" result)
(let [r (rf result)]
(println "map-t [result] post: result =" r)
r))
([result input]
(println "map-t [result input] pre: result =" result ", input =" input)
(let [r (rf result (f input))]
(println "map-t [result input] post: result =" r)
r)))))
(defn ^:static conj-t
[]
;; This is a reducer itself, not a transducer, because it doesn't receive the reducer
;; and return a reducer as a transducer.
(fn
([]
(println "conj-t []: result =" [])
[])
([result]
(println "conj-t [result]: result =" result)
result)
([result input]
(println "conj-t [result input] pre: result =" result ", input =" input)
(let [r (. clojure.lang.RT (conj result input))]
(println "conj-t [result input] post: retrun =" r)
r) )))
The oupput is edited to facilitate the understandings.
(def xform (comp (filter-t odd?) (map-t #(* % 10))))
(transduce xform (conj-t) [1 2 3 4 5])
;>> conj-t []: result = []
;
; filter-t [result input] pre: result = [] , input = 1
; map-t [result input] pre: result = [] , input = 1
; conj-t [result input] pre: result = [] , input = 10
; conj-t [result input] post: retrun = [10]
; map-t [result input] post: result = [10]
; filter-t [result input] post: result = [10]
;
; filter-t [result input] pre: result = [10] , input = 2
; filter-t [result input] post: result = [10]
;
; filter-t [result input] pre: result = [10] , input = 3
; map-t [result input] pre: result = [10] , input = 3
; conj-t [result input] pre: result = [10] , input = 30
; conj-t [result input] post: retrun = [10 30]
; map-t [result input] post: result = [10 30]
; filter-t [result input] post: result = [10 30]
;
; filter-t [result input] pre: result = [10 30] , input = 4
; filter-t [result input] post: result = [10 30]
;
; filter-t [result input] pre: result = [10 30] , input = 5
; map-t [result input] pre: result = [10 30] , input = 5
; conj-t [result input] pre: result = [10 30] , input = 50
; conj-t [result input] post: retrun = [10 30 50]
; map-t [result input] post: result = [10 30 50]
; filter-t [result input] post: result = [10 30 50]
;
; filter-t [result] pre: result = [10 30 50]
; map-t [result] pre: result = [10 30 50]
; conj-t [result]: result = [10 30 50]
; map-t [result] post: result = [10 30 50]
; filter-t [result] post: result = [10 30 50]
;=> [10 30 50]
From the above output, my conclusion is that the init part(with no argument) of reducer is called only in the last reducer(conj-t in this case) and never called in the reducers within the transducers(filter-t and map-t).
If you give the init value to the transduce function as follows,
(transduce xform (conj-t) [] [1 2 3 4 5])
;>> filter-t [result input] pre: result = [] , input = 1
; map-t [result input] pre: result = [] , input = 1
; conj-t [result input] pre: result = [] , input = 10
; conj-t [result input] post: retrun = [10]
; map-t [result input] post: result = [10]
; filter-t [result input] post: result = [10]
;
; filter-t [result input] pre: result = [10] , input = 2
; filter-t [result input] post: result = [10]
;
; filter-t [result input] pre: result = [10] , input = 3
; map-t [result input] pre: result = [10] , input = 3
; conj-t [result input] pre: result = [10] , input = 30
; conj-t [result input] post: retrun = [10 30]
; map-t [result input] post: result = [10 30]
; filter-t [result input] post: result = [10 30]
;
; filter-t [result input] pre: result = [10 30] , input = 4
; filter-t [result input] post: result = [10 30]
;
; filter-t [result input] pre: result = [10 30] , input = 5
; map-t [result input] pre: result = [10 30] , input = 5
; conj-t [result input] pre: result = [10 30] , input = 50
; conj-t [result input] post: retrun = [10 30 50]
; map-t [result input] post: result = [10 30 50]
; filter-t [result input] post: result = [10 30 50]
;
; filter-t [result] pre: result = [10 30 50]
; map-t [result] pre: result = [10 30 50]
; conj-t [result]: result = [10 30 50]
; map-t [result] post: result = [10 30 50]
; filter-t [result] post: result = [10 30 50]
;=> [10 30 50]
even the init part(with no argument) of reducer(conj-t in this case) is not called as above.
Wiithin into and sequence functions, the init part(with no argument) of reducer are never called as follows.
(into () xform [1 2 3 4 5])
;>> filter-t [result input] pre: result = () , input = 1
; map-t [result input] pre: result = () , input = 1
; map-t [result input] post: result = (10)
; filter-t [result input] post: result = (10)
;
; filter-t [result input] pre: result = (10) , input = 2
; filter-t [result input] post: result = (10)
;
; filter-t [result input] pre: result = (10) , input = 3
; map-t [result input] pre: result = (10) , input = 3
; map-t [result input] post: result = (30 10)
; filter-t [result input] post: result = (30 10)
;
; filter-t [result input] pre: result = (30 10) , input = 4
; filter-t [result input] post: result = (30 10)
;
; filter-t [result input] pre: result = (30 10) , input = 5
; map-t [result input] pre: result = (30 10) , input = 5
; map-t [result input] post: result = (50 30 10)
; filter-t [result input] post: result = (50 30 10)
;
; filter-t [result] pre: result = (50 30 10)
; map-t [result] pre: result = (50 30 10)
; map-t [result] post: result = (50 30 10)
; filter-t [result] post: result = (50 30 10)
;=> (50 30 10)
(sequence xform [1 2 3 4 5])
;>> filter-t [result input] pre: result = nil , input = 1
; map-t [result input] pre: result = nil , input = 1
; map-t [result input] post: result = nil
; filter-t [result input] post: result = nil
; filter-t [result input] pre: result = nil , input = 2
; filter-t [result input] post: result = nil
; filter-t [result input] pre: result = nil , input = 3
; map-t [result input] pre: result = nil , input = 3
; map-t [result input] post: result = nil
; filter-t [result input] post: result = nil
; filter-t [result input] pre: result = nil , input = 4
; filter-t [result input] post: result = nil
; filter-t [result input] pre: result = nil , input = 5
; map-t [result input] pre: result = nil , input = 5
; map-t [result input] post: result = nil
; filter-t [result input] post: result = nil
; filter-t [result] pre: result = nil
; map-t [result] pre: result = nil
; map-t [result] post: result = nil
; filter-t [result] post: result = nil
;=> (10 30 50)
However, I don't understand the last output in which every 'result' prints nil.
2016년 3월 10일 목요일 오전 10시 15분 43초 UTC+9, Sean Corfield 님의 말: