HN 日本語サマリー

← 一覧へ戻る
プログラミング

私たちは言語を変更できるようになるべきだ

We Should Be Able to Change Our Languages (jimmyhmiller.com)

58 pointsby surprisetalk36 コメント

要約

この記事は、プログラミング言語のカスタマイズ、特にマクロの使用に対する抵抗について論じています。過去にはコードの可読性や保守性を損なうという懸念がありましたが、現代のLLM(大規模言語モデル)の進化により、複雑なコードの理解が容易になったため、マクロの利便性が再評価されるべきだと主張しています。著者はTypeScript向けの新しいマクロツール「Sweetener」を紹介しています。

全文翻訳

プログラミング言語は固定された成果物です。委員会や、非常に賢い一人の人物によって定義されます。それらは、良い理由のために、永遠に固定された神聖な成果物です。自分のニーズに合わせてプログラミング言語をカスタマイズするという考えは、決して行うべきではない抜本的な措置です。少なくとも、人々はそのように振る舞います。ソフトウェアがますます柔軟で、成形可能で、編集可能になっている世界で、私たちのプログラミング言語はこの変化に抵抗します。その代わりに、私たちは信じられないほど複雑なビルドシステムを構築します。私たちが言語に持っていたいセマンティクスを与える複雑な規約を作成します。既存の言語構造を再利用し、異なる意味を与えます。私たちは、言語への変更を提唱するために委員会を形成し、永遠に議論を続けます。なぜなら、個々のコードベースが独自の決定を下すことを許すという考えは、私たちの感性を不快にさせるからです。 なぜ私たちは抵抗するのか 人々が自分の望むように言語を定義できる能力は新しいものではありません。それは困難ではありません。しかし、数十年にわたって大きな反発がありました。人々はこの機能を提供する言語を避けます。それを持っている言語でさえ、一部のチームはそれを完全に禁止することを選択します。しかし、これは正確にはなぜでしょうか?議論の最も率直なバージョンは、レイモンド・チェンの2005年のブログ投稿「フロー制御マクロに対するランティング」で非常によく述べられていると思います。フロー制御マクロを作成すると、言語を変更することになります。私が「.cpp」で終わるファイルのエディタを起動するとき、私が目にするのはC++であり、C++に強く似ているが、そうでない場所では異なる奇妙な方言ではないことを期待します。チェンは投稿の本文で、これらの種類の制御フローマクロは、デバッグ時に理解する必要があるものを不明瞭にすると主張しています。それらはコードの実際の操作を隠します。それらは(この場合)cppファイルに期待されるセマンティクスを、デバッグ中の人にすぐに知られていない新しいセマンティクスに置き換えます。マクロの作成者だけがそれらを理解し、他のすべての人にとっては、それらは障害となるという議論は、この種の力を強く持つ言語の大きな支持者でさえ、多くの人に echo されています。マクロは、言語設計が得意でない人々が、助けにならないツールと、あまりにも強力な効果を使って、言語設計に相当することをすることを奨励します。これにより、後から参加する人々や、時間が経過した後の作成者にとってコードが読みにくくなります。よく設計されたマクロは十分に文書化されていますが、これはあまり起こりません。 - リチャード・P・ガブリエル ガブリエルはマクロに完全に反対しているわけではありません。しかし、人々がそれらを記述することにためらっています。ほとんどの人が満たさない基準があると考えています。さて、もちろん、他の議論も与えることができます。しかし、私は、それらがこの同じ光でキャストできない議論を聞いたことがないことを認めます。マクロでいっぱいのコードを読むのは混乱します。あなたは新しいプログラミング言語を読んでおり、私たちはそれらをそれほど頻繁には学びません。人々がマクロを嫌うのは、Googleがジェネリクスなしの言語を作ったのと同じ理由です。それらは物事をより複雑にします。 これらの理由は通用するのか? 正直に言うと、私はマクロに対する議論を決して説得力があるとは思いませんでした。私が実際に見た制御フローマクロは、チェンが心配していたまさにその問題を解決するために導入されました(私はClojureにいましたが、cppではありませんでした)。それらは、各サイトのリソースがうまく処理されることを保証しました。各呼び出しサイトでコードを何度も監査する必要はなく、マクロのポイントで一度だけ監査すればよかったです。しかし、私の読者のほとんどが同じように感じているとは思いません。独自の言語構造を定義することは依然として物議を醸しており、これらの議論は多くの人の心に重みを持っています。したがって、私はあなたを説得しようとします。時代は変わったと。今日のプログラミングの状態を考えると、批判を真剣に受け止めたとしても、マクロはもはや深刻な問題ではありません。 コードを理解することがかつてないほど容易になった 今日、あなたはローカルの専門家を見つけたり、元の作成者に相談したり、Stack Overflowで質問して誰かが答えてくれるのを待ったり、長い時間をかけて試したりドキュメントを読んだりして複雑なコードを理解することに依存していません。代わりに、LLMを使用して、学習方法に合った方法で理解を深めることができます。私にとって、これはしばしばカスタムビジュアライゼーション、デモ、そしてますます具体的な質問をすることを含みます。しかし、時には簡単な説明と例で十分です。最近見つけた、私が完全に理解できなかったコード(マクロ関連ではない)を考えてみてください。 export type _ActionCreatorWithPreparedPayload< PA extends PrepareAction<any> | void, T extends string = string > = PA extends PrepareAction<infer P> ? ActionCreatorWithPreparedPayload< Parameters<PA>, P, T, ReturnType<PA> extends { error: infer E } ? E : never, ReturnType<PA> extends { meta: infer M } ? M : never > : void これは、個々の部分が何をしているのかをある程度推測できますが、なぜそして何をしているのかを理解するのは私にとって難しい種類のコードです。すべての詳細に迷ってしまいます。しかし、Claudeに2つの質問をしたことで、すべてが私にとって明確になりました。理解できない場合は、同じことをしてください。過去よりもはるかに簡単になったことを見てください。 コードの各ビットを理解することは、これまで以上に重要ではなくなりました 誰も読んで理解していないコードをコミットするという考えには、かなりの論争があります。私は常に、十分に大きく、十分に古く(そして十分に醜い)コードベースで働いてきました。それらのコードベースに書かれたすべてのコードを誰も理解していません。実際、書かれたコードの多くは、書かれたときでさえ理解されていなかったとさえ主張します。だから、この考えは私にとってそれほど物議を醸すものではありません。しかし、人々は、コードの下を誰も理解せずに今日達成できることを目の当たりにし始めていると思います。完全で有用なアプリケーションを構築できます。複雑なプロジェクトを立ち上げることができます。物事は劇的に変化しています。チームがよりよく理解できるということが、最適ではないコードを作成することが理にかなっていた時期がありました。なぜなら、コードの変更は、コード自体が最適であることよりも多くのビジネス価値を提供し、チームがそれを理解していなければ、誰も変更できませんでした。しかし、これはますますそうではなくなっています。あなたによって、可読性と理解可能性を犠牲にしてでも、コードをより速く、より良くすることができるなら、AIはそれと完璧に連携できるなら、なぜしないのですか? Sweetener、TypeScriptのためのマクロ だから、マクロの時期が熟したと思います。AIはマクロの記述を容易にします。AIは複雑なマクロの理解を容易にします。コードのデバッグは容易になりました。そして、後で触れるように、AIによって書かれたコードはマクロから大いに恩恵を受ける可能性があると思います。しかし、まだ問題があります。言語にはそれらがありません。少なくとも強力なものはありません。Cスタイルのマクロはカウントされません。Rustは、それらが言語構造ではなく、明示的で区切られたものであるように、マクロを意図的に制限しています。Lispは人々にとってあまりにも奇妙です。短い期間、SweetJsは完璧な乗り物でした。しかし残念ながら、その書き直しが放棄されたため、もはやその目的を果たしませんでした。そこで、私はそのアイデアを復活させ、現在はTypeScriptを対象とし、Sweetenerと名付けました。 私たち自身の構造 それでは、Sweetenerのマクロでできることの簡単なツアーをしましょう。パイプ演算子は、JavaScriptにとってほとんど確実に死んだ、議論の多い提案です。これは(私の意見では)パイプ演算子の良いバージョンです。シンプルなスレッドファーストバージョン。 import { (|>) } from "./macros.sts" for syntax; function map... function reduce... export const total = [1, 2, 3] |> map((n) => n * 2) |> reduce((sum, n) => sum + n, 0); export const longest = ["pipes", "read", "left", "to", "right"] |> map((word) => word.length) |> reduce((most, length) => Math.max(most, length), 0); 10年近く委員会を待つのではなく。私たちは演算子を自分で作成できます。そして、この演算子を作成するために必要なコードは何でしょうか? export operator (|>):expr { fixity infix; associativity left; precedence 35; rule { $value:expr |> $function:ide