OCaml の ml は
Meta Language の ML!
「ML」と聞いて、まず思い浮かべるのは?
そもそも「ML系言語」とは?
Standard ML・OCaml・F# など、初代 ML の系譜に連なる関数型言語ファミリー。共通する設計哲学は「厳密な型安全性と、記述の簡潔さの両立」。
- 静的型付け
- Hindley–Milner 型推論 — 型注釈はほぼ不要。コンパイラが自動で型を導出するため、スクリプト言語のような簡潔さで記述できる。
- 代数的データ型 × パターンマッチ
- 式指向・関数型ファースト
# let rec sum = function | [] -> 0 | x :: rest -> x + sum rest;; val sum : int list -> int = <fun> (* ← 型注釈ゼロ。型は全部コンパイラが推論 *)
annotation burden はほぼゼロ。それでも型検査は完全。
「動的言語のような柔軟な記述力を持ちながら、静的型付けによる強固な安全性を担保する。だから、コンパイルが通れば大体動く。」
証明を安全に操るための、
Meta Language。
- 1970年代、Edinburgh 大学の Robin Milner が、定理証明支援系 LCF (Logic for Computable Functions) のために設計。
- LCF は、論理式や証明そのもの(object language)を安全に操作するプログラムを書くための言語を必要とした。それが ML = Meta Language。
- 型システムの目的は、最初から「証明の捏造を防ぐ」こと。抽象型で
theoremを守り、正しい推論規則を通してしか値を作れないようにした。 - 「不正な状態を型で表現不可能にする」という発想は、半世紀近く経った今の OCaml にもそのまま受け継がれている。
(ML)
─────▶
(論理式・証明)
歴史と、進化。
半世紀前に誕生した「最初のML」から、言語の血脈は用途に合わせて枝分かれしてきました。その設計思想は、現代の言語にも深く息づいています。
LCF のメタ言語。
Caml Lightを経て実用化。
オブジェクト指向層を追加。
そして今:定理証明支援系 Rocq/Coq
実装言語は OCaml。
「Object Language を操作する Meta Language」という原点は、令和の時代でも現役。
静的型付けの限界突破。
「型が厳しいと書きづらい」という常識を覆す、OCaml ならではの強力な機能たち。安全性を妥協することなく、高い表現力とパフォーマンスを両立させています。
Polymorphic Variant
let f = function | `A -> "A" | `B -> "B"
Algebraic Effects
type _ Effect.t += Yield : unit Effect.t let () = match Effect.perform Yield with | () -> print_endline "resumed" | effect Yield, k -> Effect.Deep.continue k ()
Well-Typed Format Strings
(* C言語ならコンパイルは通り、実行時にゴミの値が出る(UB)罠 *) Printf.printf "%d items" "42" (* ❌ OCamlはコンパイル時エラー: *) (* Error: This constant has type string but *) (* an expression was expected of type int *)
Structural Polymorphic Equality
[ { a: 1 } ] === [ { a: 1 } ]
[ (1, "a") ] = [ (1, "a") ]
Jane Street で使われている爆速 fork:
「OxCaml」
Jane Street が実際の金融システムの本番環境で稼働させている OCaml の方言(Dialect)。「Rust の対抗馬」として、OCaml の簡潔さを保ちながらシステムプログラミングの領域へ踏み込む。
高い生産性
───▶
Race Free
◀━━━━▶
所有権による静的メモリ管理
メモリ制御
GC(ガベージコレクション)を回避するスタック割り当てと、メモリレイアウトの直接制御。Rustのような低レイヤに近いパフォーマンス最適化が可能。
データ競合フリーな並行性
「モード(Modes)」と呼ばれる型システムの拡張により、マルチコア環境におけるデータ競合を静的に防ぐ。
抜群の書き心地
最大の魅力は「ライフタイム地獄」がないこと。OCaml の強力な型推論と簡潔な構文のまま、安全で高速なプログラムを気持ちよく書ける。
OCaml は、実はコンパイルが超高速。
$ time opam switch create . 5.4.1 # ← OCaml 5.4.1 をゼロからビルド <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><> 🐫 [...] ∗ installed ocaml-compiler.5.4.1 # ← ここでコンパイラ本体のビルド完了! ∗ installed ocaml-base-compiler.5.4.1 [...] Done. real 1m19.930s # ← 全て含めて、約80秒
Machine info: Apple M4 Pro | 14 cores (10P/4E) | 48GB RAM | macOS 15.7.9
「OCaml 5.4.1 コンパイラ本体 + 標準ライブラリのフルビルドが、たったの約80秒。」
さあ、Meta Language の
世界へ。
半世紀前、証明支援系のために生まれた言語は、いま定理証明から静的解析、マイクロ秒を争う電子取引まで現役。次に触るのは、あなたの番。
Polymorphic Variant
型の事前定義(宣言)なしで、アドホックにタグ付きユニオンを使える。AST(抽象構文木)の拡張や、JSONのような動的構造のパースに威力を発揮。
(* 事前定義なしでいきなり使える *) let to_int = function | `Int i -> i | `String s -> int_of_string s (* 後から型を拡張・合成できる(Extensibility) *) type num = [ `Int of int | `Float of float ]
Algebraic Effects
async/await や Monad(bind の連鎖)による Function Color Problem を解決。非同期処理を direct style に書ける。
(* 昔(Monadic style) *) let fetch_data () = Lwt.bind (http_get "url1") (fun a -> Lwt.bind (http_get "url2") (fun b -> Lwt.return (a ^ b))) (* 今(Direct style + Effect) *) let fetch_data () = let a = http_get "url1" in let b = http_get "url2" in a ^ b
Well-Typed Format Strings
単なる文字列に見える %d や %s のフォーマット指定子を、コンパイラがASTレベルで解析し、引数の型と厳密にチェックする。
(* これはコンパイルが通る *) let () = Printf.printf "Hello %s, you have %d messages\n" "Alice" 3 (* C言語ではコンパイルが通り、実行時にゴミの値が出力される(未定義動作/UB)危険なコード *) (* ➔ OCamlは「コンパイル時」に型エラーとして完全に防ぐ *) let () = Printf.printf "Count: %d\n" "five" (* Error: This constant has type string but *) (* an expression was expected of type int *)
Structural Polymorphic Equality
Rust の #[derive(PartialEq)] や Haskell の deriving (Eq) のようなボイラープレート(お決まりの記述)が一切不要。入れ子のタプルもリストも木も、そのまま (=) で中身を比較できる。
type tree = Leaf of int | Node of tree * tree let t1 = Node (Leaf 1, Leaf 2) let t2 = Node (Leaf 1, Leaf 2) let is_same = (t1 = t2) (* => true; NB: deriving は不要 *)