読者です 読者をやめる 読者になる 読者になる

「ISLISPを使うべきでないたった1つの理由」に関して

「ISLISPを使うべきでないたった1つの理由」( http://d.hatena.ne.jp/Isuzu_T/20130623/1372003378 )が誤解している点について、簡単にまとめておこうと思います。

要点

上記はてなダイアリーから引用しますが、

マクロは,実行準備時に展開される,いかなる実行時情報も使えない.

仕様にあるこの一文が悲しみです.「実行時情報」が使えないということは,つまり,自分で定義した関数によるマクロの展開は行えない,ということです.なぜなら,関数が定義されるのは,実行時だからです.

ひとつめの引用の、規格票中の文は意訳などではなく、原文(英語)の仕様にもきっちり対応する文がありますので翻訳の問題などではありませんが、もしこのような誤解が多いようであれば削ったほうが良いような気もします。「実行準備」については仕様がある表現ですが、「実行時情報」(runtime information)という表現は仕様の中でここ以外には出てきません。

ユーザーが定義した関数をマクロの定義中で使うことの、このような視点(実行準備と実行)から見た可否については、類推っぽくなりますが、マクロの定義とその使用の関係から考えることができるでしょう。

マクロの展開は全て実行準備時に行われるわけですが、最上位のdefmacro形式によるマクロの定義は実行準備(時)ではなく、実行されて定義されるわけです。ですから、別の箇所でそのマクロが使用されて「実行準備時に展開され」る時に、そのマクロはそれ以前に「defmacro形式が実行されて、定義されたもの」ということになります。

同様にして、マクロの展開関数中で、それ以前にdefun形式により定義されている関数を使用することも問題ないと考えることができるでしょう。以下はこの話題に関するぐだぐだした話です。

その他

規格票中の最初の文と似たような表現が、PCL(『実践 Common Lisp』)中にあります。同書の §8.2 「マクロ展開時 vs. 実行時」に、

 マクロ展開時に動作するコードは実行時とはまったく異なる環境で動作するので、両者の違いを常にしっかりと区別することが大切だ。これはつまり、マクロ展開時は実行時に存在するデータにはアクセスできないってことでもある。(後略)

参考のため原文も見ておくと、

It's important to keep this distinction firmly in mind because code running at macro expansion time runs in a very different environment than code running at runtime. Namely, at macro expansion time, there's no way to access the data that will exist at runtime. (後略)

http://www.gigamonkeys.com/book/macros-defining-your-own.html

ここで言っている「実行時」というのは、そのコード片(式)を含んでいる関数が実引数に適用され評価される時、という意味であって、「実行時に存在するデータ」(the data that will exist at runtime)というのは、式中にあらわれる仮引数の値、といったようなものを指しており、Lispプログラマの常識的にいってごくあたりまえのことを言っているに過ぎません。

なぜほぼ同様の表現なのに、ISLISPの規格票の解釈では、前述のような誤解をもたらしたか、ということを考えるに、おそらくISLISPのミニマリズムに起因する実行モデルの不在ではないかと思います。以下で説明します。

JISの規格票では §1.1 の「適用範囲」の b) 適用外事項 の 3) に

ISLISPテキストを実行準備する方法,及び実行のために準備されたISLISPテキストを起動する方法。

とあり、実行準備→実行というフェーズがどう(いかにして)進行するのか、という点の詳述が範囲外となっています。

そのため、それについての記述は、§1.3 の「オブジェクトは、実行のために準備される (prepared for execution) 。」から始まる段落で述べられている以外には、まとまって存在していませんが、これが原因ではないでしょうか。

ここで、冒頭が「オブジェクトは、」となっていることに注意が必要かと思います。これがもし「ISLISPテキストは、」となっていたら、プログラム全体がまずいっぺんに実行準備され、そして実行される、という意味になるでしょう(つまり、冒頭で引用したような、マクロ中でユーザーが定義した関数が使えない、と考えてしまうことにつながります)。しかし、「オブジェクトは、」となっていますから、ISLISPの「テキスト」(§1.7.37を参照)を構成する個々の「最上位形式」(§1.7.38を参照)について述べているのであって、「最上位形式の並び」は(仕様上は)オブジェクトにはなりませんから、「プログラム全体がまずいっぺんに実行準備され」という解釈は妥当ではない、ということになります。

そういうわけで、仕様では(それぞれの最上位形式に対応する)オブジェクトについて「実行準備され、実行される」ということのみが述べられているということは確認できたとしてよいと思いますが、最後にもう少し、マクロについて考えます。

規格票中の 8. マクロ には、その順序として「マクロは,実行準備の段階で,それを使用する前に定義しなければならない。」とありますが、もしこれに加えるなら、「展開関数中で使用する関数も、そのマクロを使用する前に定義しなければならない。」ということになるかと思います。(あるいはコンパイルの都合を考えると、マクロ定義より前に定義を必須としたほうが良い?)