Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2007-11-26

CLOSチュートリアル (3)

| 00:57 | CLOSチュートリアル (3) - わだばLisperになる を含むブックマーク はてなブックマーク - CLOSチュートリアル (3) - わだばLisperになる

Common Lisp クックブックさんのところののCLOSのチュートリアルにて新しい練習問題(CLOSチュートリアル -3.6. サブクラスと継承)が出たので挑戦!。

問題.1

今までの記述で、CLOSの機能のうち defstruct に相当するものすべてに言及してきましたか?

解答

defclass(CLOS)でフォローできるdefstructの機能というところでは、漏れなく言及されたと思うのですが…。見た感じでは、defstructはもう少し多機能なようです。

問題.2

構造体を使っているアプリケーションを取ってきて、defclass を使って書き直しなさい。

解答

ぱっと思い付いたのが、ポール・グレアム氏のANSI Common Lispの二重リンクリスト(日本語版P183辺り)だったので、それをお題に書き直してみることにしました。

(defclass thread ()
  ((prev :initarg :prev :accessor THREAD-uncdr :initform nil)
   (data :initarg :data :accessor THREAD-car :initform nil)
   (next :initarg :next :accessor THREAD-cdr :initarg nil)))

;; なんとなくthreadpを追加
(declaim (inline threadp))
(defun threadp (obj)
  (typep obj 'thread))

(defun thread->list (lst)
  (if (threadp lst)
      (cons (thread-car lst) (thread->list (thread-cdr lst)))
      lst))

(defun thread-insert (x lst)
  (let ((elt (make-instance 'thread :data x :next lst)))
    (when (threadp lst)
      (if (thread-uncdr lst)
          (setf (thread-cdr (thread-uncdr lst)) elt
                (thread-uncdr elt) (thread-uncdr lst)))
      (setf (thread-uncdr lst) elt))
    elt))

(defun thread-cons (&rest args)
  (reduce #'thread-insert args
          :from-end t :initial-value nil))

(defun thread-remove (lst)
  (if (thread-uncdr lst)
      (setf (thread-cdr (thread-uncdr lst)) (thread-cdr lst)))
  (if (thread-cdr lst)
      (setf (thread-uncdr (thread-cdr lst)) (thread-uncdr lst)))
  (thread-cdr lst))

たまたま眺めていたMaclispのソースに二重リンクリストのコードがあって、二重リンクリストのことをスレッドと呼んで、car、cdr、uncdr(その名の通り逆のcdr)としていたので、そういう名前にしてみました。…名前はそのままにしておいた方が良かったような…。結果としては殆ど元のコードそのままで、defstructからの変更は殆どなし。

;; 動作
(setq th (thread-cons 'x 'y 'z))

(thread-car th)
;=> x
(thread->list (thread-cdr th))

;=>(Y Z)

;(thread->list th)

;=> (X Y Z)

(thread->list (thread-remove th))
;=> (Y Z)

defstructと違ってprint-functionの指定ができないようなので、結果を一々thread->listしないと見辛いですが、同じように動作しています。

問題.3

今使っている処理系で、nil のクラス継承階層( class-precedence-list)を調べなさい。

解答

とりあえず、手元の処理系で、

(let ((cpl #+sbcl 'sb-mop:class-precedence-list
	   #+allegro 'mop:class-precedence-list
	   #+lispworks 'class-precedence-list
	   #+clisp 'clos:class-precedence-list))
  (funcall cpl (find-class nil)))

(mapc #'print (sb-mop:class-precedence-list (find-class nil)))

を試してみましたが、全部エラーで、NILってクラスはないよ、ということでした。

;; SBCL
;; => error There is no class named NIL.

;lisp works 
;; => There is no class named NIL.

;; Allegro
;; => Error: No class named: NIL.

;; CLISP
;; => *** - FIND-CLASS: NIL does not name a class