K2NR.ME

このエントリーをはてなブックマークに追加 Tweet

transducersとcore.async

これはClojure Advent Calendarの14日目です。

Transducders自体に関しての説明はRich本人の説明が素晴らしいし、僕も以前ブログで言及したので省略します。ついでにcore.asyncも基本的な使い方は理解している前提で記事を書きます。

一番上の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使っていきましょう。

comments powered by Disqus