先日の言語ツールキットに関連して、 (Gaucheの)shiroさん*1から コメントをいただいた。貴重な意見だと感じるので、ここに全文再掲。
文法のデザインは、ハフマン符号化のようなものかもしれません。基本は「良く使うものを書きやすく」ですが、それをすると、その影で書きにくくなる部分があります。例:演算子など、lexerにとって特殊な意味をもつ文字を増やす→識別子にその文字が使えなくなる。中置記法を使う→その演算子が2項演算に限定される(haskell方式を使わない限り)。そもそも、「良く使う」ものが特別扱いされているということを覚えておかねばならない、等。最後のものは、言語設計者の考える使用法と、言語ユーザの考える使用法がずれている場合に、ユーザの負担になります。
使う人のバックグラウンドや対象となる問題領域にかかわらない、グローバルに最適な「良く使うもの」を決められるとするか否かで、立場が分かれると思います。
そのようなグローバルな最適点は無くて、最適な解は個々の問題を解くプログラマのみが知っている、とする立場に立つと、「良く使うもの」を言語設計者が決め過ぎるのはpremature optimizationになります。この立場では、なるべく文法規則を単純で一様なものにしておき、必要ならプログラマが問題に合わせてカスタマイズする、という方向になります。これがLispやTclの立場だと思います。
一方、問題の対象が限定されればされるほど「良く使う」操作に関して予測が立てやすくなるので、最適化が成功しやすくなるでしょう。シェーダー言語に、汎用的配列とは別に2〜4要素のベクタと配列を扱う文法レベルでのサポートがあるのは大いに意味があります。
問題の対象を一切限定しないで、グローバルに最適な文法をデザインできるか、はかなり未知なる領域だと思います。
これくらい切れ味の良い文章が書きたいものだ。私の文章と言ったら...。
まあ、それは置いといて、このコメントを切り口として文法のデザインについて考えてみたい。
shiroさんは「問題の対象を一切限定しないで、グローバルに最適な文法をデザインできるか、はかなり未知なる領域」とあいまいに表現してらっしゃるが、私はすべてをカバーするのことは、はっきり無理だと思う。 だから「premature optimizationを避けるため単純で一様なものを選択する」のが「LispやTclの立場」だというのは、 十分理解できる戦略である。
しかし、TclやLispは「単純で一様」ではあるが、 多くの人にとって、とっつきにくいのも事実である。 また、あらゆる局面に対応するためにあらゆるカスタマイズが可能なのは良いとしても、 あまりに柔軟に変化しうるので、結局提供される共通項は大枠(メタ文法)だけということになりかねない。 となると、「単純で一様」なものですべてをカバーしようと思うと、 無理が出るような気がする。
ふむ。最適な文法をデザインしようとすれば「バックグラウンドや対象となる問題領域」によっては、 premature optimizationになる。 しかし、それを避けて「単純で一様なものを選択する」ことは(それを好む人がいる一方で)、 とっつきにくさを生んでしまうし、柔軟性によってかえって消費脳力が増えてしまう(かもしれない、私の仮説)。
鍵は「あらゆる領域をカバーすることはない」ということだろうか。 すべてに最適な文法が存在できなくても、たとえば仮に、 80%で有効で、 残りのうち10%が可能である(残り10%はすっぱりあきらめる)、 という文法が存在できるとすれば、 その文法には十分価値があるのではないだろうか。
(比較的オーソドックスな)プログラマビリティを提供する文法を仮定すると、 この「80%に有効な文法」というのはけっこう可能なところではないだろうか。
さて、仮に言語ツールキットを本当に作るとして*2、 成功するために必要そうな条件について、後日考察してみることにしよう。
初心者に優しくないと評判のまつもとです(苦笑)。
この辺のまつもとさんの発言はパラドキシカルなもので、「そういう発言をすると良心的な初心者は(良心的なので)結局萎縮する一方、良心的でない初心者は(良心的じゃないので)そんな発言は気にしないか、逆切れする」ということで、実はあんまり益のない発言だと思うのですがどうでしょう>まつもとさん
確かにそうかも。いや、その辺はあえて無視して、 良心的な初心者にはたたみかけるように「萎縮するな」と(ある意味無茶を)呼びかけ、 そうでない初心者は相手にしないってのが私の立ち位置かもしれません。
実は、若干エゴイスト入ってる私には、 「困った初心者」に悩まされないことの方が、 初心者を助けることよりも重要だったりするかもしれません。
ところで、初心者に優しいが、そればっかりやってRubyの開発が全然進まないまつもとと、 初心者の扱いは他人に任せるがRubyの開発はばっちりのまつもととどっちがお好みでしょう? みなさん。
期待はともかく、なんとなく正体は「初心者にも優しくなく、開発も進まないまつもと」のような気がしないでもないんですが。
いずれにしても、高橋さんの
私見では、MLには「give and take」などは存在しません。あるのは「質問・ネタフリという貢献」と「回答・応答という貢献」だけ、つまりgiveしかないのです。
という言葉には賛成です。
shelarcyさんのツッコミに、 ぜんぜん分からないなどと返事してしまったが、 ちょっと考えたら、一部は理解できてきた。これくらいすぐ理解しろよって感じだが。
要するに
ということが要点のようだ。
ここは反論として、なぜツールに言語を組み込むことがナンセンスでないか、を示すべきだろう。 ただし、「DSLはナンセンス」という主張はしない。 っていうか、ユーザと開発者がそれを望むならDSLはナンセンスどころか優れたアプローチだと思うし。 ただ、組み込み言語がナンセンスであるほど万能のソリューションではない、と言うだけ。
考えるに、言語(DSL)が主ではいけない技術的な理由はない。 プログラマブルなツールと、そのツールが持つすべての機能を利用できるDSLとでは、 技術的には差は全くないだろう。 にもかかわらず、いまだに私は「成功するためには言語主・ツール従ではなく、ツール主・言語従」であるべきだと考えている。
なぜか。
最大の理由は「ユーザと開発者の心理」である。
DSLをポンと渡されて自由に使いこなせるユーザは少ない(と思う)。 まずは提供されるツールを使い、 それを拡張したいと考えた時にはじめてプログラム機能を使いツールを強化していく、 というのが一般的なユーザエクペリエンスではないだろうか。 となると必然ツール主体が望ましいということにはならないだろうか。
開発者もDSLを作りたいと言う人は少数派だ(と思う)。 たくさんいる「ツールを作りたい開発者」が自分のツールにプログラム機能が欲しくなった時の答えとして 「じゃあ、あなたのツールを機能ごとにばらばらにして、この言語から使えるようにすれば立派なDSLになりますよ」というのは、あんまり喜ばれないんじゃないだろうか。 むしろ「この言語ツールキットをリンクして機能を登録してやれば、 あなたのツールがプログラマブルに」と言ってあげた方が、 (たとえ実際の作業の本質がほとんど大差なくても)心地よく聞こえるのではないだろうか。
成功するためには、心理的な側面も重要だ*1。
ところで、shelarcyさんの意見だが実はまだ理解できないところがある。
*1 ここで「だから、Lispや関数型言語は広まらないんだ」なんて暴言は思っても吐いてはいけない。そんなこと言ってませんからねー。言ってないってば