00:00:00
01 / 11
# 俺の勉強会 #7 — Lightning Talk · 5 min

OCaml の ml は
Meta Language の ML!

「ML」と聞いて、まず思い浮かべるのは?

Haochen Kotoi-Xie  ·  Kotoi-Xie Consultancy, Inc. (KXC)  ·  github.com/haochenx
00
# 00 · 前提 ;;

そもそも「ML系言語」とは?

Standard ML・OCaml・F# など、初代 ML の系譜に連なる関数型言語ファミリー。共通する設計哲学は「厳密な型安全性と、記述の簡潔さの両立」。

  • 静的型付け
  • Hindley–Milner 型推論 — 型注釈はほぼ不要。コンパイラが自動で型を導出するため、スクリプト言語のような簡潔さで記述できる
  • 代数的データ型 × パターンマッチ
  • 式指向・関数型ファースト
utop — OCaml toplevel
# let rec sum = function
    | [] -> 0
    | x :: rest -> x + sum rest;;
val sum : int list -> int = <fun>
(* ← 型注釈ゼロ。型は全部コンパイラが推論 *)

annotation burden はほぼゼロ。それでも型検査は完全。

「動的言語のような柔軟な記述力を持ちながら、静的型付けによる強固な安全性を担保する。だから、コンパイルが通れば大体動く。」

01
# 01 · 起源 ;;

証明を安全に操るための、
Meta Language。

  • 1970年代、Edinburgh 大学の Robin Milner が、定理証明支援系 LCF (Logic for Computable Functions) のために設計。
  • LCF は、論理式や証明そのもの(object language)を安全に操作するプログラムを書くための言語を必要とした。それが ML = Meta Language
  • 型システムの目的は、最初から「証明の捏造を防ぐ」こと。抽象型で theorem を守り、正しい推論規則を通してしか値を作れないようにした。
  • 「不正な状態を型で表現不可能にする」という発想は、半世紀近く経った今の OCaml にもそのまま受け継がれている。
Meta Language
(ML)
manipulates
─────▶
Object Language
(論理式・証明)
02
# 02 · 歴史 ;;

歴史と、進化。

半世紀前に誕生した「最初のML」から、言語の血脈は用途に合わせて枝分かれしてきました。その設計思想は、現代の言語にも深く息づいています。

1973 ML
Robin Milner。
LCF のメタ言語。
1985 Caml
フランス Inria。
Caml Lightを経て実用化。
1996 OCaml
Xavier Leroy。
オブジェクト指向層を追加。
Standard ML
ML から分かれた正統な子孫。形式的意味論を持つ。
F#
OCaml のコア言語をベースに、.NET 向けに設計。

そして今:定理証明支援系 Rocq/Coq

実装言語は OCaml。

「Object Language を操作する Meta Language」という原点は、令和の時代でも現役。

03
# 03 · 独自機能 ;;

静的型付けの限界突破。

「型が厳しいと書きづらい」という常識を覆す、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

TypeScript
[ { a: 1 } ] === [ { a: 1 } ]
false
OCaml
[ (1, "a") ] = [ (1, "a") ]
true
04
# 04 · OxCaml ;;

Jane Street で使われている爆速 fork:
OxCaml

Jane Street が実際の金融システムの本番環境で稼働させている OCaml の方言(Dialect)。「Rust の対抗馬」として、OCaml の簡潔さを保ちながらシステムプログラミングの領域へ踏み込む。

OCamlGCによる
高い生産性
拡張
───▶
OxCamlno-alloc変数
Race Free
対抗
◀━━━━▶
RustBorrow Checker
所有権による静的メモリ管理
Stack Allocation & Unboxed Types

メモリ制御

GC(ガベージコレクション)を回避するスタック割り当てと、メモリレイアウトの直接制御。Rustのような低レイヤに近いパフォーマンス最適化が可能。

Race-Free Checks

データ競合フリーな並行性

「モード(Modes)」と呼ばれる型システムの拡張により、マルチコア環境におけるデータ競合を静的に防ぐ。

Pleasant to Write

抜群の書き心地

最大の魅力は「ライフタイム地獄」がないこと。OCaml の強力な型推論と簡潔な構文のまま、安全で高速なプログラムを気持ちよく書ける。

05
# 05 · 知ってました? ;;

OCaml は、実はコンパイルが超高速。

Terminal
$ 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
世界へ。

半世紀前、証明支援系のために生まれた言語は、いま定理証明から静的解析、マイクロ秒を争う電子取引まで現役。次に触るのは、あなたの番。

ありがとうございました  ·  Haochen Kotoi-Xie  ·  github.com/haochenx
SUPPLEMENT
S1
# 独自の強み ① ;;

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 ]
SUPPLEMENT
S2
# 独自の強み ② ;;

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
SUPPLEMENT
S3
# 独自の強み ③ ;;

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 *)
SUPPLEMENT
S4
# 独自の強み ④ ;;

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 は不要 *)
OCaml の ml は Meta Language の ML! · 2026.08.24