Education‎ > ‎Closer to Clojure‎ > ‎

Closer to Clojure 06: Polymorphism

Clojure supports run-time polymorphism. The run-time polymorphism is exactly late binding (run-time dispatch) of functions. In many classical object-oriented languages methods (or member functions) are binded to type (class) declaration of variable receiver (or this). (In CLOS you can refer to not only the type declaration but also value of the variable.) On Clojure you can declare run-time dispatch function by defmulti, and define methods which are called by this dispatching. To illustrate:

user=> (defmulti encounter (fn [x y] [(:Species x) (:Species y)]))
user=> (defmethod encounter [:Bunny :Lion] [b l] :run-away)
user=> (defmethod encounter [:Lion :Bunny] [l b] :eat)
user=> (defmethod encounter [:Lion :Lion] [l1 l2] :fight)
user=> (defmethod encounter [:Bunny :Bunny] [b1 b2] :mate)
user=> (def b1 {:Species :Bunny :other :stuff})
user=> (def b2 {:Species :Bunny :other :stuff})
user=> (def l1 {:Species :Lion :other :stuff})
user=> (def l2 {:Species :Lion :other :stuff})
user=> (encounter b1 b2)
:mate
user=> (encounter b1 l1)
:run-away
user=> (encounter l1 b1)
:eat
user=> (encounter l1 l2)
:fight

You can use class, returning the class of the data, as a dispatching function.

user=> (defmulti what-am-i class)
user=> (defmethod what-am-i Number [arg] (println arg "is a Number"))
user=> (defmethod what-am-i String [arg] (println arg "is a String"))
user=> (defmethod what-am-i :default [arg] (println arg "is something else"))
user=> (what-am-i 19)
19 is a Number
user=> (what-am-i "Hello")
Hello is a String
user=> (what-am-i true) 
true is something else

Inheritance is not supported in Clojure.

References:
http://clojure.org/runtime_polymorphism
http://java.ociweb.com/mark/clojure/article.html
実行時ポリモーフィズムはサポートされます.実行時ポリモーフィズムとは関数のレイトバインディング(実行時ディスパッチ)であり,古典的なオブジェクト指向言語ではメンバ関数(メソッド)が変数this(変数receiver)の型定義にバインドされます.(CLOSでは変数の型だけでなく変数の値も参照できます.)Clojureはdefmultiによって実行時ディスパッチ関数を指定し,ディスパッチ先の関数をdefmethodで定義します.次の例を見てください.

user=> (defmulti encounter (fn [x y] [(:Species x) (:Species y)]))
user=> (defmethod encounter [:Bunny :Lion] [b l] :run-away)
user=> (defmethod encounter [:Lion :Bunny] [l b] :eat)
user=> (defmethod encounter [:Lion :Lion] [l1 l2] :fight)
user=> (defmethod encounter [:Bunny :Bunny] [b1 b2] :mate)
user=> (def b1 {:Species :Bunny :other :stuff})
user=> (def b2 {:Species :Bunny :other :stuff})
user=> (def l1 {:Species :Lion :other :stuff})
user=> (def l2 {:Species :Lion :other :stuff})
user=> (encounter b1 b2)
:mate
user=> (encounter b1 l1)
:run-away
user=> (encounter l1 b1)
:eat
user=> (encounter l1 l2)
:fight

ディスパッチ関数としてデータのクラスを返すclassを使うとこんなことができます.

user=> (defmulti what-am-i class)
user=> (defmethod what-am-i Number [arg] (println arg "is a Number"))
user=> (defmethod what-am-i String [arg] (println arg "is a String"))
user=> (defmethod what-am-i :default [arg] (println arg "is something else"))
user=> (what-am-i 19)
19 is a Number
user=> (what-am-i "Hello")
Hello is a String
user=> (what-am-i true) 
true is something else

インヘリタンスはサポートされていません.

参考
http://clojure.org/runtime_polymorphism
http://java.ociweb.com/mark/clojure/article.html
Comments