threading macros便利

clojureを書いていると(reduce f4 (filter f3 (map f2 (map f1 lis))))みたいなのがネストしまくって、ソースが横に長くなるときがある(というかよくよくある)。clojureにはそういうのを解決してくれるマクロがいてそれは"->"と"->>"。名前はthread-first macroとthread-last macroだそうだ。括弧のネストした一番深いところから上がっていく順に書いていけばいい。firstとlastの違いは二つめも引数を固定にするか一つ目を固定にするか、という感じらしい。

例えばこんなtwitterのjsonデータからtweetの部分と取り出して、単語に分割、全部小文字にする、というのをマクロを使わずに書いてみる。

;; not so bad
(def words-in-tweets
     (map lower-case
	  (flatten (map (fn [tweet] (split #"\s" tweet))
			(map (fn [tweet] (tweet :text)) tweets-in-english)))))

(take 10 words-in-tweets)
; ("vanaaf" "eventjes." "kleren" "uit" "zoeken" "voor" "stage" "+" "school" "feest")

見たまんまとは言え、かなり横長である。これをthread-last macro(mapのlist部分、すなわち第二引数が省略された感じになっている)を使うと

(def words-in-tweets
     (->> (map (fn [tweet] (tweet :text)) tweets-in-english)
	  (map (fn [tweet] (split #"\s" tweet)))
	  (flatten)
	  (map lower-case)))

というようにすっきりと処理の流れが見え、かつ横長にならないというのを達成できる。素晴しい。てか、Rにも同様のことがすごい起きるのでRにも欲しい。。。