Clojure 1.5から、「some->」、「some->>」というマクロが追加されているみたいです。Clojureを使うのを再開してから、1.5の情報とかをチェックしていたわけではなかったので、知らなかったのがちょっともったいなかったですかね。
で、どういうマクロかといいますと、以前「->」と「->>」という2つのマクロについてのエントリを書きました。
Clojureの->マクロと->>マクロ
http://d.hatena.ne.jp/Kazuhira/20120617/1339947683
これの途中でnull(というかnil)が登場したら、処理を打ち切ってnilを返却するバージョンです。
一応、説明も含めて簡単にご紹介。
some->
「->」マクロは、「->」マクロの次に書いた値を、それ以降の関数呼び出し時の第1引数として扱うものです。関数呼び出しが続く場合は、その結果が次の関数の第1引数になります。
「some->」マクロは、この動きに途中の関数呼び出し結果がnilになったら、その時点でnilを返却してしまうものです。
いくつか例をご紹介。
(def nosqls {:redis {:type "Key Value Store" :url "http://redis.io/" :other "Crazy Fast"} :cassandra {:type "Column Database" :url "http://cassandra.apache.org/" :other "Multi Master"} :mongodb {:type "Document Database" :url "http://www.mongodb.org/"} :hbase {:type "Column Database"}}) (assert (= (some-> nosqls :redis :other) "Crazy Fast")) (assert (nil? (some-> nosqls :memcached :other))) (assert (nil? (some-> nil :foo :bar)))
nosqlsというvarに対して、:redis→:otherという関数呼び出しは成功するので、結果が返りますが、:memcachedは存在しないのでnilになります。また、「some->」自体をnilに対して使うことも可能です。
nullセーフになりますね。
some->>
続いて、「some->>」マクロ。
「->」マクロが関数呼び出しの最初の引数になったのに対して、「->>」マクロは関数呼び出しの最後の引数になるのでした。
なので、「some->>」マクロも関数呼び出しの最後の引数となるような動作をします。その中で、途中の結果がnilになればやっぱり処理を打ち切ってnilを返却します。
こちらも、サンプルを。
(assert (= (some->> (range) (take 10) (map #(* % 10)) (reduce +)) 450)) (assert (nil? (some->> (range) ((fn [a1 a2] nil) "dummy") (map #(* % 10)) (reduce +))))
ちょっと良い例が思いつかなくて、匿名関数を使ってちょっと無理やりな例にしてしまいました。
両方とも、知っているとコーディングの幅が広がりそうなマクロですね。