目立たないけど便利な Clojure の関数を紹介してみる

Clojure 楽しいですね。今年の 8 月くらいから勉強していて、いい機会なのでアドベントカレンダーに参加してみようと思いました。
私はあまりまだ Clojure に慣れてないので clojure.core のネームスペースからあまり目立たないけど意外に便利な関数を紹介してみたいと思います。

## alter-meta!

他のネームスペースから Var を持ってきて別名をつけようとしたりするときに、落ちてしまうメタ情報を付与したいときに使えます。

```clj
example.core> (def my-inc #'clojure.core/inc)
#'example.core/my-inc
example.core> (clojure.repl/doc my-inc)
-------------------------
example.core/my-inc
  nil
nil
example.core> (alter-meta! #'my-inc merge
                (select-keys (meta #'clojure.core/inc) [:doc :arglists]))
{:line 37, :column 14, :file "*cider-repl example*", :name my-inc, :ns #object[clojure.lang.Namespace 0x3b450d77 "example.core"], :doc "Returns a number one greater than num. Does not auto-promote\n  longs, will throw on overflow. See also: inc'", :arglists ([x])}
example.core> (clojure.repl/doc my-inc)
-------------------------
example.core/my-inc
([x])
  Returns a number one greater than num. Does not auto-promote
  longs, will throw on overflow. See also: inc'
nil
```

## bit-flip

データベースに真偽値を直接入れることが出来なくて、 tinyint なんかで実装するとデータベース上では 0 or 1 になるんですが、これを反転させたいときとかに便利です。

```clj
example.core> (bit-flip 1 0)
0
example.core> (bit-flip 0 0)
1
```

## bound?

動的束縛を使う場合、宣言時に初期値を与えないケースがあって、そういうときに `nil?` などとして確かめようにも値に束縛されていないので `false` になってしまいます。
そういうときに何にも束縛されてないことを確かめるために使います。

```clj
example.core> (def foo)
#'example.core/foo
example.core> (bound? foo)
ClassCastException clojure.lang.Var$Unbound cannot be cast to clojure.lang.Var  clojure.core/bound?/fn--5267 (core.clj:5283)
example.core> (bound? #'foo)
false
```

## butlast

`rest` の逆になります。一番最後だけを取り除きたいときというのはたまにあるので覚えておくと使えます。

```clj
example.core> (butlast [1 2 3])
(1 2)
```

## dedupe 

これはあまり使わなさそうですが、 `distinct` のように全ての重複を取り除く( like `set` )のではなくて、連続した重複のみを排除します。

```clj
example.core> (dedupe [1 2 3 3 4 5 1 2 3])
(1 2 3 4 5 1 2 3)
```

## extenders

プロトコルが何に継承されているのか知ることが出来ます。

```clj
example.core> (defprotocol Plus1 (plus1 [x]))
Plus1
example.core> (extend-protocol Plus1 String (plus1 [x] (str x 1)))
nil
example.core> (extend-protocol Plus1 Number (plus1 [x] (inc x)))
nil
example.core> (extenders Plus1)
(java.lang.String java.lang.Number)
```

## fnil 

たまに使います。ある関数に `nil` が渡されたときに `nil` の代わりに渡すものを予め決めた新しい関数を返す関数です。

```clj
example.core> ((fnil inc 0) nil)
1
example.core> ((fnil inc 0) 1)
2
```

## keep

`map` と `remove` を足したような関数。 `map` したあとに `nil` を削除したいときに使えます。

```clj
example.core> (defrecord Product [code name])
example.core.Product
example.core> (defn new-product
                 ([code] (map->Product {:code code}))
                 ([code name] (map->Product {:code code :name name})))
#'example.core/new-product
example.core> (def products
                [(new-product "CLJ01" "clj-v1")
                 (new-product "CLJ02" "clj-v2")
                 (new-product "CLJ03" "clj-v3")
                 (new-product "CLJ04")
                 (new-product "CLJ05")])
#'example.core/products
example.core> (keep :name products)
("clj-v1" "clj-v2" "clj-v3")
```

## max-key

全ての引数に対して関数を適用して返ってきた数値が一番大きいものを返します。

```clj
example.core> (apply max-key - (range 10))
0
example.core> (apply max-key val {:foo 100 :bar 20 :baz 50})
[:foo 100]
example.core> (max-key :age {:name "miu" :age 22} {:name "mixu" :age 20})
{:name "miu", :age 22}
```

## ns-unalias

特定のネームスペースからエイリアスを削除します。 REPL でエイリアス付けてしまったけど使わなくなったときなどに使えます。

```clj
example.core> (require '[clojure.string :as str])
nil
example.core> (str/join ", " (range 10))
"0, 1, 2, 3, 4, 5, 6, 7, 8, 9"
example.core> (ns-unalias *ns* 'str)
nil
example.core> (str/join ", " (range 10))
CompilerException java.lang.RuntimeException: No such namespace: str, compiling:(*cider-repl example*:171:14) 
```

## rand-nth 

主にテストデータを作るときなどに重宝します。

```clj
example.core> (rand-nth [:foo :bar])
:bar
example.core> (rand-nth [:foo :bar])
:foo
```

## reduce-kv

`reduce` に対してマップを渡したときによく使う `(fn [x [k v]])` をもっと素直に書けるようにした関数です。

```clj
example.core> (reduce-kv #(+ %1 %3)
                         0
                         {:foo 10
                          :bar 20
                          :baz 30})

60
```

## take-nth

シーケンスから偶数個目だけを取り出すなどということが簡単に出来ます。

```clj
example.core> (defn coerce [& bindings]
                {:pre [(zero? (rem (count bindings) 3))]}
                (let [params (take-nth 3 bindings)
                      fns    (take-nth 3 (drop 2 bindings))]
                  (map #(%1 %2) fns params)))
#'example.core/coerce
example.core> (coerce  42 :as str,
                       5/2 :as long)
("42" 2)
```

## when-first

シーケンスの先頭だけを束縛する `when` です。

```clj
example.core> (when-first [x (range 10)]
                (prn x))
0
nil
```

## まとめ

簡単ですが、私が便利だなって思う関数を紹介してみました。 Clojure は楽しい言語ですね！