(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は含まれていなければ読み込むという意味です. アレグロコモンリスプaclでは,標準環境で,
<cl> *features* (:UNIX :SUN4 :SUN :ALLEGRO :ALLEGRO-V3.0 :COMMON-LISP :EXCL :FRANZ-INC :GSGC)というように*features*が初期設定されています. そのため,アレグロコモンリスプでは,最初の方が定義として 使われ,Xlispでは後者が使われます. アレグロコモンリスプの場合の定義にある, excl::make-lexical-closure は,アレグロコモンリスプ特有の組み込み関数です. これは引数のフォームを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の引数のフォームに現れる変数がレキシカルバインディ ングされているものとして取り扱うためこのような変換を行なわなくてもよい ということになっています.