最小の ML コア

リージョンもエフェクトも 4 つのバックエンドもセルフホストも、その前に、Mere はまず実際に動く言語である必要があった。最小の実コア —— Hindley–Milner 推論、代数的データ型、パターンマッチ、REPL —— と、なぜ最小から始めるのか。そして、明示的であることを誇る言語で、推論される型がどう折り合うのか。

meretype-inferencehindley-milnerreplcompiler

Mere の野心的な部分 —— 明示的なメモリモデル、能力としてのエフェクト、4 つの バックエンド、ブラウザでの自己コンパイル —— はどれも何かに取り付く。その何かとは、 小さくありふれた ML コアだ。そして、面白いアイデアのどれよりも先にそれを作ったのは、 意図した選択だった。

実際の言語である最小のもの

最初の目標は紙の上では立派に見えない:プロンプトに打ち込むと答えが返る言語。リテラルと 算術、let、関数と適用、iflet rec fact = fn n -> if n < 1 then 1 else n * fact (n - 1) in fact 6 と書いて 720 が見える、それで十分だ。

その答えを生む pipeline が、他のすべてが伸びていく背骨だ:

ソース → 字句解析 → 構文解析 (AST) → 推論 (型) → 評価 → REPL

以降のどの章も、この段階のどれかの拡張だ。リージョンとエフェクトは型を拡張する。 4 つのバックエンドは「評価」を「コード生成」に置き換える。セルフホストは背骨全体を Mere 自身で書き直す。背骨を正しく・動く形にすること —— どんなに小さくとも端から 端まで —— が、そのどれかを野心的にするより先だった。

それから、電卓を ML に変える機能が来た:代数的データ型パターンマッチ、 タプル、そして多相型 —— 'a option、リスト、木。これらは言語の残りが組み上がる 素材の形なので、早くに存在する必要があった。自分自身のデータを表現しマッチできない コンパイラは、育てないコンパイラだ。

明示的であることを重んじる言語での、推論

正面から向き合う価値のある緊張がある。最初の回で、Mere は暗黙を明示にすると述べた。 今回は Hindley–Milner 型推論 を足す —— fn n -> n + 1 と書けば、あなたが言わずとも コンパイラが int -> int を導く機構だ。型を推論するのは、明示的であることの反対では ないのか?

そうではない。そしてその区別こそが要点だ。Mere が明示的にするのは、実行時の表現や 挙動がひそかに変わりうるもの —— メモリの所有権、エフェクト、スレッド越境。すべての 束縛に int と書かせる商売はしていない。ありふれた型は推論で再構成される。それらは そもそも危険な挙動を隠す部分ではなかった。第 1 回の冗長さの予算は、検証可能性を買う ところ —— エフェクトとメモリ —— に使い、機械が容易に復元できる注釈には使わない。

だから推論と明示性は対立しない。同じ方針を二つの側から見たものだ。推論して安全な ものは推論する。そうでないものは表に出す。HM は前半を無料で与えてくれる。まさに それがコアに属する理由だ:ありふれた部分を静かに保ち、明示的な部分を際立たせる。

具体的には、let 多相を伴う HM だ:let 束縛の関数は一般化されるので、let id = fn x -> x はある場所で int、別の場所で str に使え、各使用は新鮮に具体化される。これは ML の最低条件であり、後の型システムの仕事 —— リージョン、Send / Sync —— が、 それと格闘するのではなく上に取り付く土台だ。

なぜ最小か、なぜ先か

小さく始めるのは謙遜ではない。方法論だ。プロジェクト全体は、設計上の問いを 実際の プログラムを走らせて 答える —— dogfooding —— で動く。そして動くコアが無ければ何も 走らせられない。順序は強制される:

  • 高階コードで自分のエフェクト設計が窮屈だと気づくには、まず高階コードを書けねば ならない。
  • リージョン注釈がうるさすぎると分かるには、人が(あるいは自分が)実際に書く言語に リージョンが取り付いていなければならない。
  • 4 つのバックエンドを互いに突き合わせて検証するには、4 つすべてが実装する言語が なければならない。

だから最小コアは、連載の残りを測る計器だ。意図的に退屈にしてある:堅く、意外性のない ML、読めば正しさを確かめられる類のもの —— それが、第 1 回の通り、眼目そのものだ。 面白い決定は、それが存在した に、動く言語だけが投げかけられる問題への答えとして やってくる。

そのコアが据わり —— 推論、データ型、マッチ、いじれる REPL —— 野心的な部分が始まる。 最初は、Mere がその周りに作られたとさえ言える一手:メモリの扱いだ。

← Back to Mere: 言語を作る