Transducerとは

Clojure 1.7より追加されたライブラリ. 一言でいえば, リッチーヒッキーがreduceを進化させて高速化させたもの.

  • reduce(高階関数) の概念を拡張.
  • シーケンス関数から変換命令だけを抜き出したもの.
  • 変換処理の過程で生成される中間生成物としての lazy seqがコストなのでこれを省略できる.
    • 巨大なシーケンスの処理を高速に実行したいときに威力を発揮.
  • 合成可能なアルゴリズム変換.
  • 入力源や出力先によらず各要素を変換.

Transducerの定義

ClojureのCollectionを処理する関数のうちcollを引数に持たない場合は, 大抵それがtransducerの関数となっている.

(filter odd?) ;; 奇数をフィルタするトランスデューサーを返す
(map inc)     ;; incによるマッピングを行うトランスデューサーを返す
(take 5)      ;; 最初の5つの値を取得するトランスデューサーを返す

そしてこれらのtransducerを組み合わせるには comp を使う.

(def xf
  (comp
    (filter odd?)
    (map inc)
    (take 5)))

慣例として, xfとかxformとかいう名前で定義されることが多い.

トランスデューサーの使い方

sequence

reduceを伴わずに単にmap/filterを重ねたい場合.

(def xform
  (comp (filter odd?)
        (map inc)))
 
(sequence xform (range 10)) ;; => (2 4 6 8 10)

transduce

transduce は coll を即時に(遅延評価せずに)reducing関数 f にトランスデューサー xform を適用してreduceを行う.

sequence関数の末尾にreduceをくっつける感じ.

(transduce xform f coll)
(transduce xform f init coll)

into

into をつかうと, トランスデューサーを入力コレクションに適用し、出力コレクションを新たに構築する.

(into [] xf (range 1000))

Transducer 派生ライブラリ

🔧cgrand/xforms

Clojure: データラングリングで活用が期待.

✅xforms/transjuxtで統計量をまとめて計算

シーケンスに何らの計算をして要約統計量を求めたいとき, シーケンスを一回舐めれば計算が終われば理想的だが, それぞれの関数にシーケンスを通しているとそれは冗長になる.

そんな課題をx/transjuxtは解決してくれる.

例えば, 平均, 個数, 分散, 合計などなどをまとめて計算したい場合. xformsで用意されている関数ではなく, 自前関数を使いたい場合は x/reduceで関数を包む.

(into {} (x/transjuxt {:mean  x/avg
                       :mix   x/min
                       :max   x/max
                       :sum   (x/reduce +)
                       :sd    (x/reduce kixi/standard-deviation)
                       :count x/count} spreads))

References

Transducer Topics

💡reducing functionとtransducerの定義

まずは用語の定義, 大事なので注意.

reducing function とはaccumulateされた結果と新しいinputを合わせて新しいaccumulateを生成する関数. (accumulateがなんと訳すのかわからないけど, いわゆるreduce関数だ).

;; reducing function signature whatever, input -> whatever


transducer とはあるreducing functionを別のreducing functionに変換する.

;; transducer signature (whatever, input -> whatever) -> (whatever, input -> whatever)

💡TransducerはLazySeqの中間生成物コストがないためスレッディングマクロより高速

Transducerとはmapやfilterのcollectionを省いて変換処理だけ抜き出してまとめたもの. スレッディングマクロで表現されるような4つの処理をたとえば2つをまとめて操作として抽象したり, さらにその関数値を引数にすれば部分的に交換な部品ができたりする.

(->> coll
    (map proc1)
    (filter proc2)
    (map proc3)
    (map proc4))

一番の違いは, 大きなシーケンスに対する実行速度. TransducerはLazySeqの中間生成物コストがないためスレッディングマクロより高速.

Transducerとcore.async

🔗References

あんまり日本語情報ないな…

JavaScriptを用いたtransduceの概念の説明.