Skip to content

Instantly share code, notes, and snippets.

@lagenorhynque
Last active April 2, 2018 13:02
Show Gist options
  • Select an option

  • Save lagenorhynque/e23a1ad1c0de8e70cae333b188f26b9e to your computer and use it in GitHub Desktop.

Select an option

Save lagenorhynque/e23a1ad1c0de8e70cae333b188f26b9e to your computer and use it in GitHub Desktop.

whatever -> input -> whatever という reduce 関数に渡すような関数("reducing関数"と呼ばれる)を受け取ってreducing関数を返す関数、つまり

(whatever -> input -> whatever) -> (whatever -> input -> whatever)

のことを"transducer"と呼んでいる。

cf. https://japan-clojurians.github.io/clojure-site-ja/reference/transducers

例えば (map #(* % %)) は何らかの入力データの個々の要素(数値)を2乗するtransducer(= 2引数関数を受け取って2引数関数を返す高階関数)で、ここでは 仮に xform と名付けて conj に適用するとベクター、flipした cons に適用するとリスト、 str に適用すると文字列として出力できる。

dev> (def xform (map #(* % %)))
#'dev/xform
dev> (reduce (xform #(cons %2 %1)) () (range 10))
(81 64 49 36 25 16 9 4 1 0)
dev> (reduce (xform conj) [] (range 10))
[0 1 4 9 16 25 36 49 64 81]
dev> (reduce (xform #(cons %2 %1)) () (range 10))
(81 64 49 36 25 16 9 4 1 0)
dev> (reduce (xform str) "" (range 10))
"0149162536496481"
;; より簡潔に `transduce` 関数を利用すると
dev> (transduce xform conj [] (range 10))
[0 1 4 9 16 25 36 49 64 81]
dev> (transduce xform (fn ([] ()) ([coll] coll) ([coll x] (cons x coll))) () (range 10))  ; `cons` はreducing関数として定義が不十分なため工夫が必要
(81 64 49 36 25 16 9 4 1 0)
dev> (transduce xform str "" (range 10))
"0149162536496481"

この例では出力データを切り替える一方で入力データはシーケンス固定だったが、入力データにも xform (transducer)は依存しないので、シーケンス以外にもstreamやchannelなど様々な入力を扱うことができる。

e.g. http://boxofpapers.hatenablog.com/entry/core_async

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment