Multimethods and Hierarchies

defmulti 普段から使ってますが、オプションを受け取ることが出来るということに気付いて何を受け取れるんだろうってドキュメント読んでたら :hierarchy というのが使えることに気がついた。 普段全く意識してないヒエラルキーってなんだろうって思ったので軽く調べてみた。

まぁ公式ドキュメント読めばいいんだけど。

Multimethods and Hierarchies / clojure.org

簡単に説明するとこれを利用すればマルチメソッドを横方向だけじゃなくて、縦方向にも効かせることが出来るみたい。まぁとはいえ型ベースでやればプロトコル使えるしなぁ…という印象。

簡単な例は以下の通り。

(def family-hierarchy ;; ヒエラルキーを定義する
  (-> (make-hierarchy)
      (derive ::father ::parents)
      (derive ::mother ::parents)
      (derive ::grandfather ::grandparents)
      (derive ::grandmother ::grandparents)))

(defmulti otoshidama :relationship :hierarchy #'family-hierarchy) ;; :hierarchy としてさっき作ったヒエラルキーの Var を渡す

(defmethod otoshidama :default [unknown] ;; 知らない人は 30000 円くれる
  30000)

(defmethod otoshidama ::grandparents [grandparent] ;; 祖父母は 10000 円くれる
  10000)

(defmethod otoshidama ::parents [parent] ;; 両親は 5000 円くれる
  5000)

(defmethod otoshidama ::father [father] ;; 特別に父親は 6000 円くれる
  6000)

(otoshidama {:name "パパ" :relationship ::father}) ;; => 6000
(otoshidama {:name "ママ" :relationship ::mother}) ;; => 5000
(otoshidama {:name "オバアチャン" :relationship ::grandmother}) ;; => 10000
(otoshidama {:name "オジイチャン" :relationship ::grandfather}) ;; => 10000
(otoshidama {:name "シラナイオジチャン" :relationship ::uncle}) ;; => 30000

derive って何処で使ったらいいか分からなかったけど、こういうときに使うのかーという感じ。もし、プログラム全体で使いたいヒエラルキーを登録したい場合は derive の第一引数としてヒエラルキーを渡さなければ自動的にグローバルなヒエラルキーに追加される。 defmulti もオプションとして :hierarchy を渡さないなら基本的にグローバルヒエラルキーを参照している。