transducersとcore.async
これはClojure Advent Calendarの14日目です。
Transducders自体に関しての説明はRich本人の説明が素晴らしいし、僕も以前ブログで言及したので省略します。ついでにcore.async
も基本的な使い方は理解している前提で記事を書きます。
- TRANSDUCERS ARE COMING
- “Transducers” by Rich Hickey
- Rich Hickey - Inside Transducers
- Clojure1.7のtransducersとはなにか
- clojure1.7のtransducersの中身を見てみる
一番上のCognitectの記事で「core.async
でもtransducersが使えるようになるよ」って書いてあったので使ってみた記録です。
以降の内容はclojure "1.7.0-alpha4"
とcore.async "0.1.346.0-17112a-alpha"
をもとにしています。
core.async
では、以下のようにしてchan
関数がtransducerを受け取ることができます。
(require '[clojure.core.async :as async])
; 第1引数がチャンネルのバッファサイズ、第2引数がtransducer
(async/chan 1 (map inc))
こうすると、チャンネルにput!
された値が、取り出すときにtransducerで加工されます。
(def c (async/chan 1 (map inc)))
(async/onto-chan c (range))
(async/<!! c) ; => 1
(async/<!! c) ; => 2
(async/<!! c) ; => 3
; ...
これだけなら、core.async/map
関数を使えば似たようなことが簡単に実現できます
(def c1 (async/chan))
(def c2 (async/map inc [c1]))
(async/onto-chan c1 (range))
(async/<!! c2) ; => 1
(async/<!! c2) ; => 2
(async/<!! c2) ; => 3
transducersの特徴を活かしてfiltering transducer使ったり、関数合成したりしてみます。
(def xform (comp
(map inc)
(filter even?)
(drop 3)))
(def c (async/chan 1 xform))
(async/onto-chan c (range))
(async/<!! c) ; => 8
(async/<!! c) ; => 10
(async/<!! c) ; => 12
; ...
まあ使い方は普通のtransducersと変わらないですね。便利ですね。
core.async
でもcore
ライブラリと同じようにtransducersが使えるっていうのはすごい重要なことだと思います。
transducersが基本のビルディングブロックとして確立されたclojureの未来が楽しみですね。
正式リリースはまだ先ですが、みなさんも積極的にtransducersとcore.async使っていきましょう。