CLOVER🍀

That was when it all began.

Clojureのsome->マクロとsome->>マクロ

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 +))))

ちょっと良い例が思いつかなくて、匿名関数を使ってちょっと無理やりな例にしてしまいました。

両方とも、知っているとコーディングの幅が広がりそうなマクロですね。