小さな言語はプログラミングの未来です
(chreke.com)"Little Language"とは?
- 「小さな言語」は、特定の問題を解決する目的で作られた言語
→ SQL、RegEx、Dhall、…
→ また、DSLとも呼ばれる
なぜ小さな言語が必要なのか?
- アプリケーションが大きく複雑になるにつれて、ソースコードも肥大化し、理解も難しくなった
- 新規入社者のオンボーディングが難しく、依存関係の理解不足でエラーが起きたり、コード変更の管理がますます困難になっている
- この10年でコードベースは100〜500倍に大きくなった
- Linuxカーネルは1992年に1万行で始まったが、20年後には3000万行になった
- こうしたコードは、単に「機能が増えたから」だけではない。私たちのソフトウェアの作り方が変わったからでもある
- ソフトウェアはピラミッド建設と同じで、最後の石を置くためには、その下にさらに多くの石が必要になる
トレンドを乗り越える
- 最新のOSを作るのに、本当に数百万行のコードが必要なのだろうか?
- Alan Kayは2006年のSTEPSプログラムでこの前提に挑戦した
-
私たちは、解決すべき問題に合った「言語」を作ることが、問題解決をより容易にし、しかも解決策をより理解しやすく、より小さくできると考えている
- STEPSではNileという言語を作り、4万4000行のCairoレンダラーを、およそ300行のコードで類似の機能を持つように実装した
高級言語ではなぜだめなのか?
- もっと高水準の汎用言語を作ればいいのではないか?
- 個人的には、私は汎用言語の表現力について収穫逓減(diminishing returns)の地点に達していると思う
- もっと高水準の言語とはどんな姿だろうか? Pythonを例にすると、すでにあまりに高水準で、疑似コードのように見える
- 汎用言語の問題は、自分の問題をアルゴリズムに翻訳し、そのうえで対象言語でそのアルゴリズムを表現しなければならないことだ
- 1986年、Jon BentleyのProgramming Pearlsで、Donald KnuthとDoug McIlroyを招き、単語の出現頻度を数えるプログラムを書いてもらったことがあるが、DonはPascalの派生であるWEBを使い、複雑なデータ構造とともに10ページにわたって書いた
- それに対してDougは、6行のUnixパイプ構文で
tr、sort、uniq、sort、sedなどを使って実装した
少ないほど良い Less is More
- 上のUnixコマンドは、小さな言語のもうひとつの特性も示している。
「より弱い言語と、より強力なランタイム」 - Gonzalezは「The end of history for programming」でこのトレンドを語っている
- ユーザー領域の問題をランタイム側の問題へと押し出す
- プログラムを純粋な数学的表現に近づける一方で、ランタイムの複雑さを大きく増加させる
- ユーザー領域の問題をランタイム側の問題へと押し出す
- 正規表現とSQLは、それぞれテキスト検索とデータベース操作以外は何も表現できない
- これは、ランタイムがなく、あらゆるものを表現できるCのような言語と対照的だ
- 小さな言語は、Cが持つ力のスペクトルの反対側の端に立っている
- コンピュータアーキテクチャを抽象化するだけでなく、表現できるプログラムの種類を制限することで、設計上Turing-incompleteになっている
- 非常に制限的に聞こえるかもしれないが、最適化や静的解析のための新しい次元の可能性を開く
静的解析
- より弱い言語は推論しやすく、汎用言語よりも強い保証を提供できる
- たとえば、Dhallは設定ファイルを生成するための「Total Functional Programming Language(全関数型言語)」である
- つまり、無限ループに陥る危険をなくすため、Dhallプログラムは「(1)クラッシュせず、(2)有限時間で終了する」ことを「保証」する
- (1)は、例外を投げないようにすることで達成される。失敗しうる命令はOptionalの結果値を返す(値がある場合とない場合がある)
- (2)は、再帰定義を許可しないことで達成される
- 他の関数型言語では再帰がループ実装の基本的な方法だが、Dhallでは組み込みのfold関数に頼らなければならない
- 一般的なループ構造がないということは、Dhallがチューリング完全ではないことを意味する。しかしこれは汎用目的言語ではないので、その必要はない
- 言語が小さいほど、推論ははるかに容易になる
- たとえば、Pythonプログラムに他の副作用がないか確認するのは難しいが、SQLならクエリが
SELECTで始まるかどうかを見るだけでよい
- たとえば、Pythonプログラムに他の副作用がないか確認するのは難しいが、SQLならクエリが
- Nileについては、STEPSチームがグラフィックデバッガを必要として作成しており、直接確認できる
- Nileは推論しやすい小さな言語だからこそ、こうしたことが可能になる
速度の必要性
- より強力なプログラミング言語は、バグの可能性を高めるだけでなく、性能にも悪影響を与えることがある
- たとえば、プログラムがアルゴリズムとして表現されていなければ、ランタイムは自分でアルゴリズムを選択できる
- 遅い表現は、より速いものに置き換えられる(同じ結果を出すことを証明できるという前提で)
- たとえば、SQLクエリはクエリの実行方法を指示しない
- データベースエンジンは、どのクエリプランが適切かを自由に判断して使える
- インデックスを使うか、複合インデックスを使うか、あるいはDBテーブル全体をスキャンするかなど
- 最新のデータベースエンジンは各カラムの値の分布に関する統計も収集するため、統計的に最適なクエリ計画をその場で選択できる
- もしクエリがアルゴリズムの形で書かれていたなら、こうしたことは不可能だ
- データベースエンジンは、どのクエリプランが適切かを自由に判断して使える
- Nile言語を非常に簡潔にした「秘伝のソース」のひとつは、グラフィックレンダリング用のJust-in-Timeコンパイラである「Jitblt」だ
- STEPSチームとCairoチームは議論を通じて、多くのCairoコードがピクセル合成処理を手作業で最適化するために使われていることを知った
- これは理論上はコンパイラにオフロード可能な作業だった
- CairoチームのDan Amelangが自ら進んでそのようなコンパイラを実装したものがJitbltだ
- グラフィックパイプラインの最適化作業を、何をレンダリングするかという純粋に数学的な記述から切り離せるということであり、
その結果、Nileは手作業で最適化された元のCairoコードと同じくらい高速に実行できた
Small languages, Big Potential(小さな言語、大きな可能性)
- ではSTEPSはどうなったのだろうか? Tシャツに印刷できる程度のコードで動くOSを作れたのだろうか?
- STEPSの最終成果物はKSWorldだった
- 文書エディタとスプレッドシートエディタを内蔵した完全なOS
- 1万7000行のコード
- Tシャツに収めるには少し長いコードだが、私は成功だと思う
- KSWorldの誕生は、「小さな言語」に大きな潜在力があることを示している
- しかし、まだ答えられていない問いは多い
- こうした言語同士はどうやって対話するのか?
- 共通の中間表現へコンパイルすべきなのか?
- それとも異なるランタイムが並列に存在し、標準プロトコル(UnixパイプやTCP/IPのようなもの?)で通信すべきなのか?
- あるいは各言語は、複数のホスト言語で再実装できるほど小さくあるべきなのか?
- もしかすると、これらをすべて組み合わせることこそが進むべき方向なのだろうか?
- いずれにせよ、私は私たちがソフトウェアを構築する別の方法を考え出さなければならないと確信している
- おそらく「小さな言語」たちは、その物語の一部になるかもしれない
- 重要なのは、より良いものを考え出せるだけの時間があるあいだ、それぞれの上にこれ以上レンガを積み上げ続けないことだ
7件のコメント
"
私たちは、解決すべき問題に合った「言語」を作ることが、問題解決をより容易にし、ソリューションをより理解しやすく、しかも小さくすると考えています。
"
この部分を読んで感じたのは、結局のところ「小さな言語」とはフレームワークと同じ意味なのではないか、ということです。よく使われる関数やデザインパターンを強制して一種の文法化を行った、
JavaScript -> Reactの事例のように。興味深いテーマですね。
そういえば、JetBrainsが作った MPS(Meta Programming System) というDSL生成ツールを最近見つけました。
これ、思っていたよりかなり古くからあるものなんですね。興味が湧いてもう少し調べてみようと思いつつ、あれこれあって先延ばしにしているのですが、もしこれを使ったことがある方がいれば、使用感のようなものを聞けたらうれしいです。
わあ、ありがとうございます
ありがとうございました。
Lisp にっこり
面白い話だと思ったので、紹介します。