Posted 2017-10-01 16:57:10 GMT

defclass で構造体を定義するのってできなかったっけかなあと思い、ちょっと調べてみたが、どうも structure-class との統合は未完に終わっているようで、MOPでも構造体の生成についての記述はない様子。

に類することができれば、どうにかなりそうだが、思えば構造体にそのような道具はなく、実行時に定義するならコードを生成してから eval みたいなことになりそうだ。

ちなみに、 eval が絡むと大抵

(let ((x 42)) (defstruct foo (x x) y z)) (make-foo) → #S(foo :x 42 :y nil :z nil)

みたいなことができなくなるので避けたい所。

(但し構造体については上記ができても殆ど意味がない)

構造体の定義については、 defstruct を書くしかないという結論になったが、それでは、 defclass を defstruct に展開する方向で考えてみようということで、これに使えそうな、 expand-defclass を思い出したので使ってみることにした。

proto structure-class eql 'structure-class metaclass name supers slots class-options defstruct ( ,name ( :include ,@supers ) ) ,@ mapcar lambda ( s ) if consp s car s getf cdr s :initform ,s nil slots ,@ defmethod clos::expand-defclass

これを使うと下記のように書ける

defstruct foo x y z (defclass bar (foo) ((a :initform 42) b c) (:metaclass structure-class)) (make-bar) → #S(bar :x nil :y nil :z nil :a 42 :b nil :c nil)

( foo ) ( ( a :initform 42 ) b c ) :metaclass structure-class defclass bar

をマクロ展開すると、

defstruct ( bar ( :include foo ) ) ( a 42 ) nil nil

となる。

expand-defclass について

expand-defclass は、MOPの初期(1987年頃)には存在していたが、定義構文の展開方法については具体的に規定しないことになり、定義構文のマクロ展開メソッドは諸々1988年には消えてしまった。

そのためAMOPには載っていない。

( expand-defclass prototype-instance name superclasses slots options environment )

という総称関数だが、展開がメソッドでカスタマイズできるというのが、なかなか良さそう。

なお、LispWorks版は、environment 引数は取らないが、環境は取り込んでいるので謎なことをしている様子。

なお、初期MOPの仕様にほぼ沿っている expand-defclass は、調べた限りでは、どうもLispWorksにしか存在しないようだ。

(TI ExplorerのTICLOSにはFlavorsで定義されているexpand-defclassがあったのと、Portable CommonLoopsに仕様が違う同名の関数があった。)

まとめ

Common LispもDylan位に色々統合されてくれていたら良かったのになと思ったりする。

ちなみに、Dylanでは動的さが制御できるので性能を出したい場合は制限をかけるようになっている。

また、Eclipse Common Lispは全面的にOOPで書かれているが、Dylanのように sealed 指定が可能なように拡張されていたようだ。

■

