簡潔さが力である
Original2002年5月
"代数記号によって小さな空間に圧縮された意味の量は、それらの助けによって行うことに慣れた推論を容易にする別の事情である。"
- チャールズ・バベッジ、アイバーソンのチューリング賞講演から引用
Revenge of the Nerdsで提起された問題についてのLL1メーリングリストでの議論で、ポール・プレスコッドが書いたことが私の心に残った。
Pythonの目標は正則性と可読性であって、簡潔さではない。
表面的には、これはプログラミング言語について非常に厳しい主張のように思える。私の理解では、簡潔さ=力である。そうであれば、置き換えると、
Pythonの目標は正則性と可読性であって、力ではない。
となり、これは(もしそうであれば)トレードオフとは思えない選択肢ではない。これは、Pythonの目標がプログラミング言語として効果的でないことを言っているのと同じことだ。
簡潔さ=力なのだろうか? これは私にとって重要な問題であり、言語設計に興味のある人にとって最も重要な問題かもしれず、正面から取り組むべきだと思う。まだ単純な答えはないが、良い仮説だと思う。
仮説
私の仮説は、簡潔さが力であるか、あるいはそれに近いということである。
簡潔さこそがプログラミング言語の本来の目的だと思う。コンピューターは機械語で直接指示されるだけでも満足するだろう。高級言語を開発する主な理由は、レバレッジを得ることだと思う。つまり、高級言語で10行で表現できることを機械語では1000行で書かなければならないということだ。言い換えると、高級言語の主な目的はソースコードを小さくすることである。
ソースコードを小さくすることが高級言語の目的であり、何かの力とは、その目的をどの程度達成しているかで測れるなら、プログラミング言語の力の尺度は、プログラムをどの程度小さくできるかということになる。
逆に、プログラムを小さくできない言語は、プログラミング言語として本来の役割を果たせていないと言えるだろう。切れ味の悪いナイフや、判読できない印刷物のようなものだ。
指標
では、小さいとはどのような意味なのか? コードサイズの一般的な指標は行数だ。しかし、これは最も測定しやすいからだと思う。行数がプログラムの長さの真の尺度だと誰も本気で考えているわけではない。言語によって1行にどれだけのものを書くのが慣例かが異なる。Cでは行頭の区切り記号しかない行が多い。
別の簡単な指標は文字数だが、これもあまり良くない。ある言語(Perlなど)は他の言語よりも識別子が短いからだ。
プログラムのサイズを測る better な指標は、要素の数だと思う。要素とは、ソースコードの構造を木構造で表した場合の個別のノードになるものである。変数名や関数名は要素、整数や浮動小数点数も要素、リテラルテキストの断片も要素、パターンの要素やフォーマット指示子も要素、新しいブロックも要素である。境界線上のものもあるが(例えば-5は2要素か1要素か?)、ほとんどの場合は言語に関係なく同じなので、比較にはあまり影響しないと思う。
この指標をさらに詳しく定義する必要があり、特定の言語の場合は解釈が必要かもしれない。しかし、私が測ろうとしているのは正しいものだと思う。それは、プログラムを構成する部品の数である。私が頭の中で描く木構造のサイズが、プログラムを理解したり書いたりするのに必要な作業量に比例すると考えている。
設計
この種の指標を使えば、言語間の比較ができるが、それが私にとって最も重要な価値ではない。最も重要なのは、言語の設計指針としての価値だ。言語間の最も有用な比較は、同じ言語の2つの潜在的な変種の比較だ。言語にどのような変更を加えればプログラムをより短くできるか?
プログラムの概念的な負荷がその複雑さに比例し、ある程度の概念的な負荷しか扱えないプログラマーがいるとすれば、これは「どうすればプログラマーがより多くのことを実現できるようになるか」と同じことを尋ねているのと同じだ。そして、これは私にとって「良い言語をどのように設計するか」と同じ問題だ。
(ついでに言えば、「すべての言語は同等である」という古い格言が間違っていることは、言語設計をすれば一目瞭然だ。新しい言語を設計するときは、常に「xを行えば言語がどうなるか」と「行わなければどうなるか」を比較しているのだ。これが本当に意味のない問題なら、コインを投げればいいだけだ。)
簡潔さを目指すことは、新しいアイデアを見つける良い方法だと思う。多くの異なるプログラムを短くできることを発見できれば、それは偶然ではないはずだ。おそらく、有用な新しい抽象化を見つけたのだろう。ソースコードを検索して繰り返しパターンを見つけるプログラムを書くこともできるかもしれない。簡潔さで定評のある言語、Forth、Joy、Iconなどを参考にするのも良いかもしれない。
比較
これらの問題について最初に書いたのは、私の知る限り、フレッド・ブルックスの『人月の神話』だ。彼は、プログラマーは言語に関係なく1日あたりほぼ同じ量のコードを生成するようだと書いている。私が20代の頃にこれを初めて読んだときは大きな驚きで、大きな意味を持つように思えた。
(a) ソフトウェアを速く書くには、より簡潔な言語を使うしかない、 (b) そうした努力をした人は、そうでない競争相手を大きく引き離せる
ブルックスの仮説が真実なら、ハッカーの本質に迫るものだと思う。その後、私はこの問題に関する証拠を、正式な研究からプロジェクトの逸話まで、あらゆるものに注目してきた。彼の仮説に反するものは何も見つからなかった。
私には決定的な証拠が見つかっていないし、それを期待することもできません。ルッツ・プレヒェルトの言語比較研究のような研究は、私が期待していた種類の結果を生み出しますが、意味のあるテストとしては短すぎる傾向があります。言語の真の試験は、1か月かけて書かれるプログラムでどうなるかです。そして、言語の主な目的が、コンピューターに何をするよう指示するのではなく、考えるのに良いものであると私が信じているなら、その真の試験は、それによって新しいことを書くことができるかどうかです。したがって、事前に定義された仕様に従わなければならない言語比較は、少し間違ったことをテストしているのです。
言語の真の試験は、既に誰かが定式化した問題をどれだけうまく解決できるかではなく、新しい問題を発見し解決する能力です。これら2つの基準は全く異なります。 美術では、刺繍やモザイクのようなメディアは、事前に何を作りたいかがわかっている場合に良く機能しますが、そうでない場合は全く役に立ちません。人物の画像のように複雑なものを発見しながら作る場合は、鉛筆やインクウォッシュ、油絵のような流動的なメディアを使う必要があります。実際、タペストリーやモザイクは、最初に絵を描いてから、それをコピーして作られます(「カートゥーン」という言葉は、本来このような目的で描かれた絵を指していました)。
これは、プログラミング言語の相対的な力を正確に比較することはほとんど不可能であることを意味しています。私たちは正確な比較はできますが、正確なものではありません。特に、言語を比較する目的で行われる明示的な研究は、小さな問題を使うため、そして必然的に事前に定義された問題を使うため、より強力な言語の力を過小評価する傾向があります。
現場からの報告は、「科学的」な研究ほど正確ではありませんが、より意味のあるものになる可能性があります。例えば、エリクソンのウルフ・ウィガーは、研究で、Erlangがc++よりも4-10倍簡潔で、ソフトウェア開発速度も同等であると結論付けています。
この研究はまた、ブルックスの本で暗示されていた点(デバッグ済みコードの行数を測定していた)を明示的に扱っています。つまり、より強力な言語で書かれたプログラムは、バグが少ない傾向にあるということです。これは、ネットワークスイッチのようなアプリケーションでは、プログラマー生産性以上に重要な目標となる可能性があります。
味覚テスト
最終的には、直感に頼るしかありません。その言語でプログラミングするのはどんな感じですか? 私は、最良の言語を見つける(あるいは設計する)ためには、その言語がどれだけ考えやすいかに敏感になることが重要だと思います。ある言語機能が不自然や制限的に感じられたら、それを知っておくべきです。
このような敏感さには代償がかかります。あなたは、不器用な言語でプログラミングするのを我慢できなくなるでしょう。マクロのない言語でプログラミングするのは、私には耐え難い制限的なものに感じられます。動的型付けに慣れた人が、変数の型を宣言しなければならず、異なる型のオブジェクトのリストを作ることができない言語に戻らされるのと同じように。
私だけではありません。多くのLispハッカーにもこのような経験があります。実際、プログラミング言語の相対的な力の最も正確な尺度は、その言語を知る人の何パーセントが、アプリケーションドメインに関係なく、その言語を使えるどんな仕事でも引き受けるかかもしれません。
制限性
ほとんどのハッカーは、言語が制限的に感じられるとはどういうことかよくわかっていると思います。それはどのようなことが起きているのでしょうか? 私が考えるに、行きたい道が封鎖されて、目的地まで遠回りしなければならないときに感じるのと同じ感覚だと思います。言いたいことがあるのに、その言語ではそれを言えないのです。
ここで本当に起きていることは、制限的な言語は十分に簡潔ではないということだと思います。問題は単に、計画していたことが言えないということではありません。問題は、言語に強制されるデトアーが長いということです。次のような思考実験をしてみてください。ある程度のプログラムを書きたいと思っていて、その言語がそれを直接書くことを許さず、代わりに短い別の方法で書くよう強制したとします。私にとっては、それほど制限的には感じられないでしょう。行きたい道が封鎖されて、交差点の警官に近道を教えてもらえるようなものです。素晴らしい!
制限性の感覚の90%以上は、言語に強制されるプログラムが自分の頭の中にあるものよりも長くなることから来ていると思います。制限性とは主に簡潔性の欠如です。 したがって、言語が制限的に感じられるとき、それは(主に)十分に簡潔ではないということを意味し、言語が簡潔でないとき、制限的に感じられるのです。
可読性
冒頭の引用では、正規性と可読性という2つの他の特性についても言及されています。正規性がどういうものか、また、単に可読性があるだけでなく正規性もある場合に、コードにどのような利点があるのかよくわかりません。しかし、可読性については理解できると思います。それも簡潔性と関係があると思います。
ここでは、個々の行の可読性と、プログラム全体の可読性を区別する必要があります。重要なのは後者です。Basicの行のほうがLispの行よりも可読性が高い可能性があることに同意します。しかし、Basicで書かれたプログラムはLispで書かれたものよりも行数が多くなるでしょう(特にGreenspunの領域に入ると)。Basicプログラムを読むための総労力は確実に大きくなるはずです。
総労力 = 1行あたりの労力 x 行数
可読性が簡潔性に比例するほど直接的ではないかもしれませんが、確かに簡潔性は可読性の要因(数学的な意味での)です。したがって、言語の目標は可読性であって簡潔性ではないと言うのは意味がないかもしれます。それは、可読性の目標であって可読性の目標だと言うようなものです。
行の可読性が初めて言語に出会うユーザーにとって意味するのは、ソースコードが脅威的に見えないということです。したがって、行の可読性は良いマーケティング上の決定かもしれませんが、設計上の決定としては悪いかもしれません。これは、分割払いを認めることで成功した手法と同じです。高額な前払い価格を恐れさせるのではなく、低い月々の支払いを伝えます。しかし、分割払いは買い手にとって損失になるのと同様に、行の可読性も恐らくプログラマーにとって損失になるでしょう。
買い手は多くの低い支払いをすることになり、プログラマーは多くの個別に可読性の高い行を読むことになるのです。
このトレードオフは、プログラミング言語以前から存在していました。小説や新聞記事に慣れ親しんでいる人が数学論文を初めて読むと、落胆するかもしれません。1ページを読むのに30分もかかるかもしれません。しかし、私はその記号法が問題ではないと確信しています。数学論文が読みづらいのは、アイデアが難しいからです。同じアイデアを散文で表現したら(数学者が簡潔な記号法を発展させる前はそうしていた)、本の分量になってしまい、読みやすくはないでしょう。
どの程度まで?
多くの人が、簡潔さ=力というアイデアを拒否してきました。代わりに、簡潔さと力の関係を問うことがより有用かもしれません。 簡潔さが高水準言語の目的の大部分であることは明らかです。もし簡潔さがそれらの唯一の目的ではないとすれば、他にどのような目的があり、それらの重要性はどの程度なのでしょうか。
私がこう提案するのは、議論をより文明的にするためだけではありません。答えを知りたいのです。言語がそれ自体のために過度に簡潔になることはあるのでしょうか。
私が最初に仮説としていたのは、病的な例を除いて、簡潔さと力は同一視できると考えていたということです。つまり、誰かが言語を設計する際、それらは同一視されるだろうが、この仮説を反証するために言語を設計しようとすれば、おそらくできるだろうということです。実際のところ、私もそれが可能かどうか確信がありません。
言語、プログラムではない
私たちが議論しているのは、個別のプログラムの簡潔さではなく、言語の簡潔さであることを明確にしなければなりません。 個別のプログラムが過度に密に書かれることは確かにあり得ます。
私はOn Lispでこのことについて書きました。複雑なマクロは、自身の長さの何倍もの節約をもたらさない限り、正当化されないかもしれません。ある複雑なマクロを使うことで、10行のコードを節約できるとしても、そのマクロ自体が10行あれば、1回以上使えば行数の純減になりますが、それでも良い選択とは限りません。なぜなら、マクロ定義は通常のコードよりも読みづらいからです。10回や20回使わないと、可読性の純改善にはならないかもしれません。
私は、そのようなトレードオフがすべての言語に存在すると確信しています(ただし、言語がより強力になるほど、その影響は大きくなると思います)。賢明な人が、疑わしいプログラミングテクニックを使って、わずかに短くしたコードを見たことのある programmer は誰もいるでしょう。
これについては議論の余地はありません。少なくとも私からは。個別のプログラムが過度に簡潔になることはあり得ます。問題は、言語自体が過度に簡潔になることはあり得るかどうかです。言語が programmer に、全体の可読性を犠牲にしてでも短い(要素数の少ない)コードを書かせることはあり得るのでしょうか。
言語が過度に簡潔になることを想像するのが難しい理由の1つは、何かを極端に簡潔に表現する方法があれば、おそらくそれよりも長い方法もあるということです。例えば、マクロや高階関数を多用したLispプログラムが密過ぎると感じたら、Pascalに似たコードを書くこともできます。階乗を
(rec zero 1 * 1-)
のように高階関数の呼び出しで表現するのではなく、
(rfn fact (x) (if (zero x) 1 (* x (fact (1- x)))))
のように再帰的に定義することもできます。
具体的な例は思い浮かびませんが、言語が過度に簡潔になることがあるかどうかという問題には興味があります。圧縮され、理解しづらいコードを書かざるを得ない言語はあるのでしょうか。そのような例があれば、ぜひ見せていただきたいと思います。
(注意: 私が求めているのは、上で概説した「要素」のメトリックで見て密度の高いプログラムであって、区切り文字を省略したり、すべての名前を1文字にしただけで短くなったプログラムではありません。)