先日の言語ツールキットに関連して、 (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や関数型言語は広まらないんだ」なんて暴言は思っても吐いてはいけない。そんなこと言ってませんからねー。言ってないってば
いや、「LispやTclの立場」ではあってもそれを Ruby のような言語が利用してもいいんですよ。Haskell はそれ相応の大きさの文法をもった言語ですが、Lisp のような手法が当然のように使われています。
まつもとさんは文法が変わってしまうのは好きじゃないようですけど。
http://page.freett.com/shelarcy/diary_2004-09.html#dsl_combinator
関数型言語の素養がないせいか、
* 「「LispやTclの立場」ではあってもそれを Ruby のような言語
が利用する」とか
* 「Ruby とかにライブラリを用意してやってその上に DSL を構
築」とか
* 「下のレベルのライブラリをうまく確保しさえすれば、後は
combinator を書いていくことで DSL は簡単に記述できる」とか
要するに重要な点がまったく理解できませんでした。頭悪いな>自分。
あと、「Ruby 論者はマクロ不要論を唱える」というのは事実に反
します。むしろ強硬に不要論を唱えているのは私だけじゃないかと。
数年前のRuby Conference(確か2001 Florida)では、マクロ欲しい
派と議論を戦わせたことが思い出されます。
マクロ不要論は事実誤認でしたか。
「LispやTclの立場」ではあってもそれを Ruby のような言語 が利用するというのは、言語内 DSL を利用しようよというぐらいのことでしかありません。言語内 DSL を利用することで言語の備えている一般的世界から専用の世界に行けばいいんじゃないかということで。
DSL の構築し方については、どう説明していけばいいかな……Haskell 入門者のための本である "The Haskell School of Expression" の時点で、まず C の API とのインターフェースが用意されていて、それを外部ライブラリを使っていることを悟らせないように DSL で包んでやる方法が言及されているので。
http://page.freett.com/shelarcy/diary_2004-03.
html#haskell_soe
今回の言及の元になったこの辺の記事から想像できますでしょうか?
http://d.hatena.ne.jp/tanakh/20040928#p2
Lisp だと "On Lisp" で目の前の問題を解決するべく抽象化関数を書いていくうちに DSL ができあがるという形でした。
「ある言語で……うんぬん」という場所は言語設計者ではなく言語使用者に対して呼びかけています。
C++ の template を metaprogramming に使用することで、言語設計の側も return type における型推論の導入を考え始めているように、言語使用者が設計者の考えなかった思わぬ使用法をすることで初めてそういうフィードバックが可能になります。あえて言うなら、これの大切さを呼びかけているというところですね。
この日記もRSS提供してください〜。
makerss.rb入れるだけですから。
makerss.rb をインストールしたのでツッコミのテストさせてください。
エラーが出たのでもう一度ツッコミのテストさせてください。m(_ _)m
すみません、今度こそうまくいくはず...なのでツッコミのテストさせてください。m(_ _)m
もちろん「初心者に優しくて、Rubyの開発もばっちりのまつもとさん」がお好みです :D
という好みはさておき、初心者の扱いは他人任せでぜんぜん構わないと思いますよ。
子は経験の生まれかわり。なにもしらなくても、そのやり方が、
受けつがれてる。だからわたしたちはいつも新鮮生気。プログラムは生まれかわる。人、生物のように。
親が0+1=1 1+1=2 2+1=3 … 9+1=10 … としてきた。
子はx+yが分かるかも?