(defun instance (class-name &rest args) (let ((ins (create-instance class-name (class-local-variables (get-class class-name))))) (if args (apply ins (cons ins args)) ins))) (defun create-instance (class-name vars&values) (eval `(internal-create-instance ,class-name ,vars&values))) (defmacro internal-create-instance (class-name vars-values) `(let ,vars-values #'(lambda (self x &rest args) (let ((method (find-method x ',class-name))) (if method #+:allegro (apply (excl::make-lexical-closure method) (cons self args)) #-:allegro (apply method (cons self args)) (error "~a undefined method for class ~a" x ',class-name))))))クロージャは,送られてくるメソッドがクラス(class-name)に 登録されているかどうか探しだし(find-method),そのメソッドが あればそれを実行する,というように作る. ここでは,そのメソッドがlambda式になっている. 上の定義で用いられている,#+:allegroは,*features*という 大域変数に:allegroというシンボルが含まれているかどうかを調べて, 含まれていればその次のS-式を読み込むという意味である. #-:allegroは含まれていなければ読み込むという意味である. Allegro Common Lisp(ACL)では,標準環境で,
<cl> *features* (:UNIX :SUN4 :SUN :ALLEGRO :ALLEGRO-V3.0 :COMMON-LISP :EXCL :FRANZ-INC :GSGC)というように*features*が初期設定されている. そのため,ACLでは,最初の方が定義として 使われ,Xlispでは後者が使われる. ACLの場合の定義にある, excl::make-lexical-closure は,ACL特有の組み込み関数である. これは引数のフォームをlexical-closureに変換する ものです.つまり,そのクロージャが作られた時の字ずらの 環境が保存されたクロージャを作る. 上のプログラムでは,vars-valuesの中に現れる局所変数が その環境として保存される. こうすることで,たとえば,x-positionというメソッドにおいて, インスタンス固有の変数であるx-positionの値を知りたい時に, ただx-positionを返すように書いておくだけですむことになる. この場合,vars-valuesの中にx-positionが現れ,変数methodが (lambda () x-position)という式になり, このx-positionがvars-valuesに現れたx-positionであるとみなされる ことになる. xlispの場合には,applyの引数のフォームに現れる変数がレキシカルバインディ ングされているものとして取り扱うためこのような変換を行なわなくてもよい ということになっている.