Loading...

簡潔さは力である

Original

2002年5月

「代数記号によって小さな空間に圧縮された意味の量は、私たちがその助けを借りて行う推論を容易にする別の状況です。」

  • チャールズ・バベッジ、アイバーソンのチューリング賞講演より引用

LL1メーリングリストでのRevenge of the Nerdsに関する議論の中で、ポール・プレスコッドが私の心に残ることを書きました。

Pythonの目標は、簡潔さではなく、規則性と可読性です。

一見すると、これはプログラミング言語について非常に厳しい主張のように思えます。私が知る限り、簡潔さ = 力です。 そうであれば、置き換えると、

Pythonの目標は、力ではなく、規則性と可読性です。

これは、あなたが望むようなトレードオフ(もしそれがトレードオフであるなら)ではないように思えます。 これは、Pythonの目標がプログラミング言語として効果的でないと言っているのと大差ありません。

簡潔さ = 力ですか?これは私にとって重要な質問のように思えます。 言語設計に興味のある人にとって、最も重要な質問かもしれませんし、直接対峙する価値のある質問です。私はまだ答えが単純な「はい」であるとは確信していませんが、始めるには良い仮説のようです。

仮説

私の仮説は、簡潔さは力である、または病的な例を除いてそれらを同一視できるほど近いということです。

簡潔さはプログラミング言語の目的であるように思えます。コンピュータは機械語で直接何をすべきかを指示されることに同じくらい満足するでしょう。私たちが高水準言語を開発する手間をかける主な理由は、レバレッジを得るためであり、高水準言語の10行で、機械語の1000行を必要とすることを言ったり(そしてより重要なことに、考えたり)できるようにするためです。言い換えれば、高水準言語の主なポイントは、ソースコードを小さくすることです。

もし小さなソースコードが高水準言語の目的であり、何かの力がその目的をどれだけ達成するかであるなら、プログラミング言語の力の尺度は、どれだけ小さくプログラムを作るかです。

逆に、プログラムを小さくしない言語は、プログラミング言語がすべきことをうまくやっていないことになります。これは、うまく切れないナイフや、読めない印刷物のようなものです。

メトリクス

では、小さくするとはどういう意味でしょうか?コードサイズの最も一般的な測定基準は行数です。しかし、私はこのメトリクスが最も一般的であるのは、測定が最も簡単だからだと思います。誰もが本当にそれがプログラムの長さの真のテストであるとは信じていないと思います。異なる言語には、行にどれだけの内容を入れるべきかに関する異なる慣習があります。C言語では、多くの行には区切り記号が1つか2つしかありません。

別の簡単なテストは、プログラム内の文字数ですが、これもあまり良くありません。いくつかの言語(例えばPerl)は、他の言語よりも短い識別子を使用します。

プログラムのサイズを測るためのより良い基準は、要素の数だと思います。要素とは、ソースコードを表す木を描いたときに異なるノードになるものです。変数や関数の名前は要素です。 整数や浮動小数点数は要素です。 リテラルテキストのセグメントは要素です。 パターンの要素やフォーマット指示子は要素です。 新しいブロックは要素です。境界ケースもあります(-5は2つの要素か1つか?)が、ほとんどのケースはどの言語でも同じなので、比較にはあまり影響しません。

このメトリクスは具体化が必要であり、特定の言語の場合には解釈が必要かもしれませんが、プログラムが持つ部品の数を測ろうとしていると思います。この演習で描く木は、プログラムを考えるために頭の中で作らなければならないものであり、そのサイズはそれを書くか読むために必要な作業量に比例します。

デザイン

この種のメトリクスは、異なる言語を比較することを可能にしますが、少なくとも私にとっては、その主な価値ではありません。簡潔さテストの主な価値は、言語を設計する際のガイドとしてです。 言語間の最も有用な比較は、同じ言語の2つの潜在的なバリアントの間のものです。プログラムを短くするために、言語で何ができるでしょうか?

プログラムの概念的負荷がその複雑さに比例し、特定のプログラマーが固定の概念的負荷に耐えられる場合、これは「プログラマーが最も多くのことを成し遂げるために何ができるか?」と尋ねるのと同じです。そして、それは私にとって、良い言語を設計するにはどうすればよいかを尋ねるのと同じです。

(ちなみに、「すべての言語は同等である」という古い格言が間違っていることを明らかにするものは、言語を設計することです。新しい言語を設計する際には、常に2つの言語を比較しています—私がxをした場合の言語と、しなかった場合の言語—どちらが良いかを決定するために。もしこれが本当に意味のない質問であれば、コインを投げるのと同じです。)

簡潔さを目指すことは、新しいアイデアを見つける良い方法のようです。 多くの異なるプログラムを短くする何かを行うことができれば、それは偶然ではないでしょう。おそらく、あなたは有用な新しい抽象を発見したのです。ソースコード内の繰り返しパターンを検索するプログラムを書くことさえできるかもしれません。他の言語の中で、簡潔さで評判のある言語は、新しいアイデアを探すべき言語です:Forth、Joy、Icon。

比較

私が知る限り、これらの問題について最初に書いたのはフレッド・ブルックスのMythical Man Monthです。彼は、プログラマーは言語に関係なく、1日にほぼ同じ量のコードを生成するように見えると書きました。 私が20代前半にこれを初めて読んだとき、それは大きな驚きであり、巨大な意味を持つように思えました。 それは、(a) ソフトウェアをより早く書く唯一の方法は、より簡潔な言語を使用することだということ、そして(b) これを行う手間をかけた人は、そうしなかった競争相手を置き去りにできるということを意味しました。

ブルックスの仮説が真実であれば、それはハッキングの核心にあるようです。 それ以来の数年間、私はこの質問に関する証拠に注意を払ってきました。正式な研究から個々のプロジェクトに関する逸話まで、彼を否定するものは何も見ていません。

私はまだ私にとって決定的な証拠を見たことがなく、期待もしていません。ルッツ・プレヒェルトのプログラミング言語の比較のような研究は、私が期待した結果を生み出す一方で、意味のあるテストには短すぎる問題を使用する傾向があります。言語のより良いテストは、1か月かかるプログラムで何が起こるかです。そして、もし私が信じるように、言語の主な目的が考えるのに良いことであるなら(単にコンピュータに何をすべきかを伝えることではなく)、新しいことをその言語で書けるかどうかが唯一の真のテストです。 したがって、事前に定義された仕様を満たさなければならない言語比較は、少し間違ったことをテストしています。

言語の真のテストは、新しい問題をどれだけうまく発見し解決できるかであり、他の誰かがすでに定式化した問題を解決するためにどれだけうまく使えるかではありません。この2つは非常に異なる基準です。 芸術において、刺繍やモザイクのような媒体は、事前に作りたいものがわかっている場合にはうまく機能しますが、わからない場合には全く役に立ちません。画像のような複雑なものを作るときに、作りながらその画像を発見したい場合には、鉛筆やインクの洗い流し、油絵のようなより流動的な媒体を使用する必要があります。実際、タペストリーやモザイクは、最初に絵を描き、それをコピーすることで作られます。(「カートゥーン」という言葉は、もともとこの目的のために意図された絵を指すために使用されていました。)

これは、プログラミング言語の相対的な力を正確に比較することはほとんど不可能であることを意味します。私たちは正確な比較を持つことができますが、正確なものではありません。特に、言語を比較する目的のための明示的な研究は、小さな問題を使用する可能性が高く、必然的に事前に定義された問題を使用するため、より強力な言語の力を過小評価する傾向があります。

現場からの報告は、「科学的」研究よりも正確さは劣りますが、より意味のあるものになる可能性があります。たとえば、エリクソンのウルフ・ウィガーは、ErlangがC++よりも4〜10倍簡潔であり、ソフトウェア開発においても比例して速いという研究を行いました:

エリクソン内部の開発プロジェクト間の比較は、使用された言語(Erlang、PLEX、C、C++、またはJava)に関係なく、ソフトウェア開発のすべてのフェーズを含む同様の行/時間の生産性を示しています。したがって、異なる言語を区別するものはソースコードのボリュームになります。

この研究は、ブルックスの本において暗黙的にしか触れられていなかったポイント(彼がデバッグされたコードの行数を測定したため)にも明示的に対処しています:より強力な言語で書かれたプログラムは、バグが少ない傾向があります。これは、ネットワークスイッチのようなアプリケーションでは、プログラマーの生産性よりも重要な目的となるかもしれません。

テイストテスト

最終的には、直感に従う必要があると思います。その言語でプログラミングするのはどのような感じですか?私は、最良の言語を見つける(または設計する)方法は、言語がどれだけ考えやすいかに対して過敏になることだと思います。そして、最も良いと感じる言語を選ぶ/設計します。もし何らかの言語機能が不便または制約を感じさせるものであれば、心配しないでください。あなたはそれについて知ることになるでしょう。

そのような過敏さはコストがかかります。あなたは、ぎこちない言語でプログラミングすることが耐えられないことに気づくでしょう。私はマクロのない言語でプログラミングすることが耐えられないほど制約を感じます。動的型付けに慣れた人が、すべての変数の型を宣言しなければならない言語でプログラミングすることが耐えられないほど制約を感じるのと同じです。

私は唯一の人間ではありません。私はこのような経験をした多くのLispハッカーを知っています。実際、プログラミング言語の相対的な力の最も正確な測定基準は、その言語を知っている人々のうち、その言語を使用する仕事を受け入れる人の割合かもしれません。アプリケーションドメインに関係なく。

制約

ほとんどのハッカーは、言語が制約を感じさせるとはどういうことかを知っていると思います。それを感じるとき、何が起こっているのでしょうか?私は、それは行きたい通りが封鎖されていて、目的地に行くために長い迂回をしなければならないときの感覚と同じだと思います。あなたが言いたいことがあり、言語がそれを許さないのです。

ここで本当に起こっていることは、制約のある言語は十分に簡潔ではないということだと思います。問題は、単に計画していたことを言えないことではありません。言語があなたに取らせる迂回が長いのです。この思考実験を試してみてください。あなたが書きたいプログラムがあり、言語があなたが計画した方法でそれを表現させない場合、代わりに短い別の方法でプログラムを書くことを強制されたとしましょう。少なくとも私にとって、それはあまり制約を感じさせるものではありません。それは、行きたかった通りが封鎖されていて、交差点で警官が迂回ではなくショートカットを指示しているようなものです。素晴らしい!

私は、制約を感じる感覚のほとんど(90%?)は、あなたが書くプログラムを、頭の中にあるものよりも長くしなければならないことから来ていると思います。制約は主に簡潔さの欠如です。 したがって、言語が制約を感じるとき、それは(主に)十分に簡潔ではないことを意味し、言語が簡潔でないとき、それは制約を感じるでしょう。

可読性

私が始めに引用した言葉には、規則性と可読性という2つの他の特性が言及されています。私は規則性が何であるか、または規則的で可読性のあるコードが単に可読性のあるコードに対してどのような利点があるのか、よくわかりません。しかし、可読性が何を意味するのかはわかっていると思いますし、それも簡潔さに関連していると思います。

ここで注意しなければならないのは、個々のコード行の可読性とプログラム全体の可読性を区別することです。重要なのは後者です。私は、Basicの1行はLispの1行よりも可読性が高い可能性があることに同意します。しかし、Basicで書かれたプログラムは、Lispで書かれた同じプログラムよりも行数が多くなるでしょう(特にGreenspunlandに入ると)。Basicプログラムを読むための総努力は確実に大きくなります。

総努力 = 行ごとの努力 x 行数

私は、可読性が簡潔さに直接比例するとは確信していませんが、力がそうであることは確信しています。しかし、確かに簡潔さは可読性において要素です(数学的な意味で;上記の方程式を参照)。したがって、言語の目標が可読性であり、簡潔さではないと言うことは、意味がないかもしれません。それは、目標が可読性であり、可読性ではないと言うようなものです。

行ごとの可読性が意味するのは、言語に初めて出会うユーザーにとって、ソースコードが脅威を感じさせないということです。したがって、行ごとの可読性は、悪い設計の決定であっても、良いマーケティングの決定である可能性があります。それは、人々に高い前払い価格で脅かすのではなく、低い月額料金を伝えるという非常に成功した手法に同型です。分割払いは、買い手にとっては純粋に損失ですが、プログラマーにとってもおそらくそうです。 買い手は、その低い低い支払いをたくさんすることになるでしょう。そして、プログラマーは、その個別に可読性のある行をたくさん読むことになるでしょう。

このトレードオフはプログラミング言語よりも前から存在します。小説や新聞記事を読むことに慣れていると、数学論文を読む最初の経験は驚くべきものになることがあります。1ページを読むのに30分かかることもあります。 それでも、私は記法が問題ではないと確信しています。たとえそれが問題のように感じられても。数学論文は、アイデアが難しいために読みづらいのです。同じアイデアを散文で表現した場合(数学者が簡潔な記法を進化させる前に行わなければならなかったこと)、それは読みやすくはならないでしょう。なぜなら、論文は本のサイズにまで成長するからです。

どの程度まで?

多くの人々が、簡潔さ = 力という考えを拒否しています。私は、単にそれらが同じであるかどうかを議論するのではなく、次のように尋ねる方が有用だと思います: 簡潔さはどの程度力であるか? なぜなら、明らかに簡潔さは高水準言語の大部分の目的だからです。それがすべての目的でない場合、他に何の目的があり、これらの他の機能は相対的にどれほど重要なのでしょうか?

私はこの議論をより文明的にするために提案しているのではありません。私は本当に答えを知りたいのです。言語が自らの利益のためにあまりにも簡潔すぎるのはいつですか?

私が始めに述べた仮説は、病的な例を除いて、簡潔さは力と同一視できると考えていました。私が意味していたのは、誰もが設計する言語ではそれらが同一であるが、もし誰かがこの仮説を明示的に反証するために言語を設計したいのであれば、おそらくそれを行うことができるということです。実際、私はそれすら確信していません。

言語、プログラムではなく

私たちは、個々のプログラムの簡潔さではなく、言語の簡潔さについて話していることを明確にする必要があります。 個々のプログラムがあまりにも密に書かれることは確かに可能です。

私はこれについてOn Lispで書きました。複雑なマクロは、その長さの何倍も保存しなければ正当化されないかもしれません。もし、ある厄介なマクロを書くことで、使用するたびに10行のコードを節約でき、そのマクロ自体が10行のコードであれば、1回以上使用すれば行数の純粋な節約が得られます。しかし、それは依然として悪い選択かもしれません。なぜなら、マクロ定義は通常のコードよりも読みづらいからです。可読性の純粋な改善を得るには、マクロを10回または20回使用する必要があるかもしれません。

私は、すべての言語にそのようなトレードオフがあると確信しています(ただし、言語がより強力になるにつれてリスクが高くなると疑っています)。すべてのプログラマーは、ある賢い人が疑わしいプログラミングトリックを使用して、わずかに短くしたコードを見たことがあるはずです。

したがって、それについての議論はありません—少なくとも私からはありません。個々のプログラムは確かに自らの利益のためにあまりにも簡潔すぎることがあります。問題は、言語がそうであることができるかどうかです。言語は、全体の可読性を犠牲にして、要素数が短いコードを書くことをプログラマーに強いることができるでしょうか?

言語があまりにも簡潔すぎることを想像するのが難しい理由の1つは、もし何かを表現するための過度にコンパクトな方法があれば、おそらく長い方法もあるからです。たとえば、Lispプログラムが多くのマクロや高階関数を使用してあまりにも密であると感じた場合、好みに応じてPascalに同型のコードを書くことができます。もし、Arcで階乗を高階関数への呼び出しとして表現したくない場合、

(rec zero 1 * 1-)

再帰的定義を書くこともできます:

(rfn fact (x) (if (zero x) 1 (* x (fact (1- x)))))

私は、思いつく例はありませんが、言語があまりにも簡潔すぎるかどうかの質問には興味があります。コードを書く方法が窮屈で理解できないように強いる言語はありますか?もし誰かが例を持っているなら、ぜひ見せてほしいです。

(リマインダー:私が探しているのは、上記の「要素」のメトリクスに従って非常に密なプログラムであり、単に区切り記号を省略でき、すべてが1文字の名前であるために短いプログラムではありません。)