sheepleでディスパッチ

sheepleはCLOSの総称関数の様なディスパッチ機構を持っています。

まず、「メッセージ」を定義し、「メッセージ」への各オブジェクトの「応答(reply)」を定義していきます。
「メッセージ」がCLOSの総称関数、「応答」がCLOSのメソッドにあたります。

(defmessage test (obj))
(defvar *obj1* (object))

(defreply test ((obj *obj1*))
  (write "*obj1*"))

(test *obj1*)
;; -> "*obj1*"
;; => nil

CLOSと明に違うのは、sheepleにはクラスがないため、「応答」の特定がオブジェクトに対して行なわれるところでしょうか?
ただし、「応答」の特定がオブジェクのみだと不便であるため、parentsで指定したオブジェクトに特定された「応答」も選択されます。

(defvar *obj2* (object :parents (list *obj1*)))

(test *obj2*)
;; -> "*obj1*"
;; => nil

CLのオブジェクトのプロトタイプも用意されていて、「応答」の特定の際に指定できます。

(defmessage add (a b))

(defreply add ((a =number=) (b =number=))
  (+ a b))

(add 10 20)
;; => 30

(defreply add ((a =string=) (b =string=))
  (concatenate 'string a b))

(add "hoge" "huga")
;; => "hogehuga"

最後に、fibをsheepleで書いてみます。

(defmessage fib (n))
(defreply fib ((n 0))
  1)
(defreply fib ((n 1))
  1)
(defreply fib (n)
  (+ (fib (- n 1)) (fib (- n 2))))

既に分かっている応答については、defmessageで定義できるみたいです。

(defmessage fib (n)
  (:reply ((n 0)) 1)
  (:reply ((n 1)) 1)
  (:reply (n) (+ (fib (- n 1)) (fib (- n 2)))))