2010/05/09

なぜ他の言語に、Lispのようなマクロがないのか?

前回の9LISPでも掲題のような話をしていました。私も最近このことが気になります。なんでだろう?
そこで、こういう文章があったなーと。
(Lispの意味での)マクロは、私の知る限り依然としてLispに特有のものだ。 たぶん、マクロを持つためには言語をLispと同じような奇妙な外見にしないと 駄目だからだろう。それにまた、マクロという最後の力を加えたら、 それは新しい言語ではなくLispの新しい方言になってしまうからだろう。
私はよくジョークでそういうことを言うのだが、実際それは真実なんだ。 car、cdr、cons、quote、cond、atom、eq、そして関数をリストで表現する 方法を備えた言語があれば、あなたはLispの残り全てをそれで構築することができる。 これがLispの質を定義しているんだ。McCarthyがLispにこの姿を与えたのは、 まさにそのためだったからだ。


追記2

PerlやPythonにLispのマクロに相当するものを追加することはできないのですか?
Couldn't you add something equivalent to Lisp macros to languages like Perl or Python?

追加したら、それらはLispの方言になってしまう。真のマクロは、プログラムの解析木を処理しなければならない。構文規則のある言語でこれを可能にするには、(a)ソースコードから解析木への翻訳を公開し (b)プログラムがコンパイラに行く前に、解析木の上でプログラムを走らせる事をプログラマができるようにする必要がある。
Not without turning them into dialects of Lisp. Real macros need to operate on the parse tree of the program. To allow that in a language with syntax, you have to (a) make public the translation from source code to parse trees, and (b) give the programmer the opportunity to run programs on parse trees before they go on to the compiler.

だがそうするなら、解析木用の記法を開発しなければ難しい。そしてその記法を開発したら、OS XにおいてMac OSがUnixのスキンになったのと同様、その言語はLispのスキンになってしまう。
But it would be hard to do that without creating a notation for parse trees; and once you do, your language has become a skin on Lisp, in much the same way that in OS X, the Mac OS became a skin on Unix.

ハッカーと画家 コンピュータ時代の創造者たち

5 件のコメント:

  1. 構文木の直接操作っていう意味では無いかもしれませんが、ソースレベルのメタプログラミングということなら、Perlのsource filterとか、Template Haskellとか、MetaOCamlとかがLispのマクロに該当するんじゃないでしょうか。

    そんで、ここからは2つ質問がありえると思います: (1)なんでLispのような構文木操作じゃないの? (2)なんでそれらのシステムは言語仕様に取り込まれてないの? (まあPerl5については「仕様」を議論する意味がないかもしれませんが)

    (1)については、やっぱり構文木操作とS式が密接に結びついているからかなと思います。他の言語でもリフレクションで構文木を得られるのはありますが、Lisp族ほど簡単になりません。Lispは基本的に「ソースの見た目どおり」ですからね (Schemeの場合はちょっと余分な情報がくっついてきますが)。

    また、型付き言語だとソースのローカルな字面だけじゃわからない色々な情報(推論された型とか)をコンパイラは知っているのに 、Lisp的な構文木操作だけだとそういう情報がうまく扱えなくてもったいないので、言語にもっとふさわしいマクロがあるんじゃないか、と考えるのは自然だと思います。

    そこで(2)なんですが、Common Lispのマクロというのは非常に単純なメカニズムで、一種のローカルオプティマムに達しているんじゃないかと思うのです。つまりLisp的マクロというのを突き詰めようとすると、S式+構文木操作という最適解に落ち着いちゃう。なのでLisp族に関していえば何をマクロとするかについてあまり迷いどころはありません(せいぜい健全性の話くらい)。ところが、S式+構文木操作を離れて考えると、何が最適解かはそれほど自明ではなくて、だから言語仕様に入れるほど「固まった」議論になりにくいのかなと思います。実装レベルで追加するぶんには問題ないからどんどん試されてるわけですけれどね。

    返信削除
  2. 本日は度々ありがとうございます。

    Perl, Haskell, MetaOcaml のそれぞれは、初めて知りましたので、どういうものか知りたくなりました。調べてみたいと思います。

    (1)については、非S式においてS式程簡単にいかないというのは、なんとなくですが想像できます。非S式言語でのマクロを少し見たことがありますが、Lisp以上に複雑そうでした。書くのも、きっと実装する方も難しいのだろうなーと。


    >つまりLisp的マクロというのを突き詰めようとすると、S式+構文木操作という最適解に落ち着いちゃう。
    >S式+構文木操作を離れて考えると、何が最適解かはそれほど自明ではなく

    そういうことになっちゃうんですね^^;
    記事に追記した、Rubyのまつもとさんのブログの記事でもそのようなことが書いてありました。

    返信削除
  3. Smalltalk のように、当初(Smalltalk-72)は LISP のマクロに近い感じでメソッドを書かせていた(メッセージ=マクロ名+引数 として定義に従い引数を展開)けれど、フレキシブル過ぎるという理由(the flexible syntax of the earlier Smalltalks was too flexible, and this level of extensibility was not desireable. http://bit.ly/aKYQvy )でこれは廃止され、今の単純な動的関数コール(メッセージ=メソッド名+引数 と一意に解釈し、該当するメソッドをコール)という方式に落ち着いた…と、こんなパターンもありそうです。

    Smalltalk 72 入門
    http://languagegame.org:8888/propella/74

    返信削除
  4. コメントありがとうございます。sumim さんのブログには、何かとたどり着くことがよくあります。

    >メッセージ=マクロ名+引数 として定義に従い引数を展開

    ここだけ見ると、Lispのマクロに似ていそうですね。Scheme の syntax-rules みたいなものでしょうか。Smalltalk は触ったことがないのですが(squeak はインストールするだけしているのですけど)、貼って頂いたURLの方、今から見てみます。

    返信削除
  5. S式以外では、どう作れば簡単に実装できるのかが広く知られていないのが原因だと思います。
    C式というS式に変わる言語ベースにLispのマクロを実装したサンプルがありますので参考にしてください。
    http://gist.github.com/46417

    返信削除