先日開催された人工知能プログラミングのための Common Lisp 入門(1)でスペシャル変数について議論が盛り上がりました。

動作がややこしいので議論になりやすい所ですが、自分的にはあまり深く知らなくても実際にコードを書く上ではまず問題になることはないかなという印象です。

Schemeのようにスペシャル変数がない方言もあります(後付けの parameter で似たようなことは可能)

とはいいつつ議論の上で自分的に気になったのがトップレベルの SETQ の挙動についてです。

3.1.2.1.1.4 Symbols Naming Both Lexical and Dynamic Variables から、こんなコードが引用されていたのですが、

この文脈だけでは、 x がトップレベルで special 宣言されているかどうかは分からないので、動作がこの説明の通りになるかどうかは分かりません。

HyperSpec: Declaration SPECIAL の例では、

という風にトップレベルでの宣言の有無をはっきりさせています。

ここで、おやっと思うのが (setf (symbol-value 'x) 6) という symbol-value を使っている所ではないでしょうか。

なんとなく setq が使われることが多いような…、ということで、ここからトップレベルでの setq 問題です。

トップレベルでの setq 問題については、6年位前にも書いたりしたことがありました。

トップレベルでの setq の結果はどうやら未定義動作らしい、という風に書いてありますが、当時なるほどと思った解釈は、onjoさんのLingerでの説明でした。

varの解釈での、「変数名前空間に束縛」、「どうみても変数」あたりはHyperSpecを読み込んだ上での解釈かなと思います。

とはいえ、未定義動作であると明文化されている訳ではなく、HyperSpecの setq の説明を読んでも記述は無いようです。

一応自分もHyperSpecを眺めてみましたが、 setq は、 (setq var form ...) となり、varは、variableとして説明があり、 setq は、 variable を assign するものという説明があります。

assignとは、 binding が establish された状態を変更すること、とあり、establishとは変数を作る、もしくは宣言するものとあります。 defvar / defparameter の説明を参照してみるに、 defparameter and defvar establish name as a dynamic variable. とありますが、 setq にはこのように establish する機能はなく、 assign するだけ、ということは分かります。

それで、 establish していない未束縛な変数を assign した場合ですが、これはどこに書いてあるかさっぱり不明、という感じです。

ちなみに、 setq の先祖にあたる set は、 (setf (symbol-value ...)) と同義と説明があり、値セル変更するものとの説明なので曖昧さはありません。

また、トップレベルの場合は、 setq は set と同じ挙動に切り替わるよ、というような記述も無く、飽く迄 setq は variable を相手にしているようです。

CMUCLはトップレベルで setq した場合 special 宣言をつける、というのが良く知られていますが、

トップレベルでの未定義変数の setq は未定義動作なので、 special 宣言するという動作であっても良い、という解釈なのかと思っていました。

しかし、FAQの回答を読むと、そのような言及もなく単に簡便性を取っているだけのようです。

Common Lispの仕様策定においてトップレベルのレキシカル変数を導入しようという提案がKent Pitman氏によってされていました。

結局この仕様が採用されることはなかったのですが、議論中にDavid Moon氏によるこんな発言があります。

—– Moon 21-Jan-89 —– On the above issue, CLtL unfortunately says explicitly that free references to unproclaimed and undeclared variables are SPECIAL. Also making it an error would break the current practice of just typing SETQ at the interpreter, people felt during the discussion.