世界一短い(かもしれない)オブジェクト指向フレームワーク「nekoduck」

●ソースコード
(define (object parent . methods)
  (lambda (method-name . params)
    (if (null? parent)
        (let ((root-value (assoc method-name methods)))
          (if root-value ((cadr root-value) params) 'not_found))
        (let ((my-value (assoc method-name methods)))
          (if my-value ((cadr my-value) params) (parent method-name))))))
●使い方
(define オブジェクト名
  (let ((フィールド1 初期値1)
        (フィールド2 初期値2)
                        ))
    (object 親オブジェクト名
            `(メソッド1 ,処理1)
            `(メソッド2 ,処理2)
                          ))))
  • ルートオブジェクトの場合は親オブジェクトとして空リストを指定
  • 外からフィールドにアクセスするにはアクセサを用意する
  • 継承の例は発表資料を参照
●オブジェクトの例(カウンタ)
(define counter
  (let ((c 0))
    (object '() `(up ,(lambda (p) (set! c (+ c 1))))
                `(plus ,(lambda (p) (set! c (+ c (car p)))))
	        `(show ,(lambda (p) c)))))
(counter 'show)
0
(counter 'up)
1
(counter 'plus 5)
6


【追記】
よく見たら親オブジェクトにメソッドの引数渡してなかった。ダメすぎ
引数を一つに限定して、複数の引数を渡したいときはリストを渡すようにすればOKか。コードは略


【2010-03-20追記】
親オブジェクトにメソッドの引数を渡すのはapplyでいいのに気付いた。なんでわからなかったんだろう

(define (object parent . methods)
  (lambda (method-name . params)
    (if (null? parent)
        (let ((root-value (assoc method-name methods)))
          (if root-value ((cadr root-value) params) 'not_found))
        (let ((my-value (assoc method-name methods)))
          (if my-value ((cadr my-value) params) (apply parent method-name params))))))

ついでに、カウンターのplusも任意の個数の引数を取れた方がいいよね

(define counter
  (let ((c 0))
    (object '() `(up ,(lambda (p) (set! c (+ c 1))))
                `(plus ,(lambda (p) (set! c (apply + c p))))
	        `(show ,(lambda (p) c)))))