`(Hello ,world)

ツッコミ、添削大歓迎です。いろいろ教えてください。

2008-10-21

Lisp-2の理由

Common Lispでなんで関数と変数の名前空間が分かれてる必要があるのかすごく疑問だったんだけど、理由が思いついた。もし関数と変数の名前空間が同じだと、普通のマクロを使ったときに展開して現れる関数名を let などで隠してしまった場合に動作がおかしくなってしまう。「そんなことしない」と言っても中で何で使われるかは予測不可能だから、意図せぬところで隠してしまって急に動作がおかしくなったりすると困る。でも名前空間が分かれてるから let とかで隠されたりしないから安全、やったね!というわけだ。逆に名前空間を1つにする場合は、衛生的マクロ(hygienic macro)前提ってことかな。

でも labels を使うと関数を局所定義できるので、マクロ内で使われる関数を隠したらどうなるんだろう?と思った。

(defmacro add (a b)
  `(+ ,a ,b))

(add 1 2)
;=> 3

のところを

(labels ((+ (a b)
           (cons a b)))
  (add 1 2))

とすると、xyzzy lisp では

(1 . 2)

と狙い通りになった。CLISP でも同様。labels の中でマクロを使う場合は、展開された形で使われる関数を隠さないようにしないとマズイってことですね。でもそれは無理な話だし…。

Gauche でも試してみた:

(define-macro (add a b)
   `(+ ,a ,b))

(let ((+ (lambda (a b) (cons a b))))
  (add 1 2))
;=> (1 . 2)

g000001g0000012008/10/21 12:40なるほど、なるほど。
CLにはパッケージロックという処理系依存な機能があってホームパッケージ以外の場所で再定義するとエラーにできることが多いです(SBCL)とか。→http://www.sbcl.org/manual/Package-Locks.html
あとは、備え付けの関数は再定義禁止という風に決まっていて、この2つで回避している感じですね('-'*)。

mokehehemokehehe2008/10/21 21:20おぉ、さすがにそのへんは考えられてるんですね。
Paul Graham みたいに、3文字4文字の呪文のような関数を定義しまくられると困ったことになるんじゃないかと思ったので。

mokehehemokehehe2008/11/08 06:19http://practical-scheme.net/wiliki/wiliki.cgi?Scheme%3A%E3%83%9E%E3%82%AF%E3%83%AD%3ACommonLisp%E3%81%A8%E3%81%AE%E6%AF%94%E8%BC%83
> 標準関数を(ローカル環境であっても)再束縛しない、ということがルールになっている (Allegroだと警告が出たんじゃなかったっけ? 確かめてませんが)
> 非標準の関数をマクロ展開結果に挿入する場合、その名前をパッケージプリフィックス つきで挿入すれば、マクロの使用環境 (マクロ定義環境とは別のパッケージと想定) で 同名のシンボルが使われていても衝突しない

トラックバック - http://cadr.g.hatena.ne.jp/mokehehe/20081021