Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
OCaml Meeting 2026 in Tokyo
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Masayuki Mizuno
August 22, 2026
250
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
OCaml Meeting 2026 in Tokyo
Masayuki Mizuno
August 22, 2026
More Decks by Masayuki Mizuno
See All by Masayuki Mizuno
CircleCI ユーザーミートアップ
fetburner
0
160
関数型まつり2026
fetburner
2
900
Rails アプリの docker build を 倍速にした話
fetburner
2
180
Omotesando.rb #110
fetburner
0
220
Continuation is to be continued
fetburner
1
2.4k
callccの実装を読む
fetburner
0
250
RubyでSlackのbotを作ろう
fetburner
0
220
継続オペレータの話
fetburner
0
280
Rubyでリストモナドを使う
fetburner
0
220
Featured
See All Featured
BBQ
matthewcrist
89
10k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
1k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.1k
Ruling the World: When Life Gets Gamed
codingconduct
0
310
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
480
The SEO identity crisis: Don't let AI make you average
varn
0
530
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
680
Why Our Code Smells
bkeepers
PRO
340
58k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.4k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
35
2.8k
Music & Morning Musume
bryan
47
7.3k
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
550
Transcript
OCaml Meeting 2026 in Tokyo 全てのものは関数って本当? OCamlの内部実装から見る計算機上での表現 Aug 22, 2026
- Masayuki Mizuno ©2026 Wantedly, Inc.
自己紹介 水野雅之 所属: ウォンテッドリー株式会社 職業: インフラエンジニア(2025/07〜) Twitter (現X): @fetburner mixi2:
@lgtm GitHub: https://github.com/fetburner ©2026 Wantedly, Inc.
本発表のテーマ 関数閉包をデータ構造として見る メモリ使用量や実行時間に与える影響を見ていく ©2026 Wantedly, Inc.
アジェンダ 1. チャーチエンコーディング 2. ランタイムでの関数の表現 3. 関数閉包を積極的に作るアルゴリズムの計算量 4. 計算可能性の制約を使った面白いプログラム ©2026
Wantedly, Inc.
チャーチエンコーディング 全てのものは関数である? ©2026 Wantedly, Inc.
チャーチエンコーディング 帰納的データ型を型なしλ計算で表現する手法 畳み込みを行う関数で帰納的データ型の値を表現する データ 畳み込む関数 [1; 2; 3] = 1
:: 2 :: 3 :: [] l = fun f x -> f 1 (f 2 (f 3 x)) :: ↦ f、[] ↦ x と置き換える = 畳み込み fold̲right f fun f x -> 1 :: f 1 2 :: f 2 3 :: f 3 [] (要素 1, 2, 3 はそのまま持ち越す) x l f x = f 1 (f 2 (f 3 x)) = fold_right f [1; 2; 3] x ©2026 Wantedly, Inc.
チャーチ数 自然数は与えられた関数のn回適用で表現できる ペアノ自然数の畳み込みと捉えると良い ペアノの公理 3 = 0 に「+1」を 3 回
ヴァリアントで表現 畳み込む関数 type nat = Z | S of nat fun f x -> f (f (f x)) +1 ↦ S、0 ↦ Z fun f x -> +1 S f +1 S f +1 S f 0 ©2026 Wantedly, Inc. S ↦ f、Z ↦ x (まだ計算しない) Z (畳み込み) x
ある種の関数はデータ型の表現と 対応している ©2026 Wantedly, Inc.
ランタイムでの関数の表現 ©2026 Wantedly, Inc.
OCaml実行時の関数の表現 環境と関数ポインタの組の関数閉包が使われる let make_adder z = ① 引数は a だけ。z
は外から来る = 自由変数 fun a -> a + z ② make̲adder が返ると、変数 z は消える → でも返された関数は、呼ばれた時に z が要る ③ だから z を保存して持ち歩く。その箱が環境 ̶ 関数 = 〈コードポインタ, 環境〉の組 環境(個別) コードポインタ add10 z = 10 code = make_adder 10 add1 z = 1 = make_adder 1 ©2026 Wantedly, Inc. (コードは共有・環境は個別) code fun a -> a + z のコード(機械語・共有で 1 つ)
チャーチ数の実行時表現 ペアノの公理に従って帰納的に定義した自然数と同型 ※匿名関数を直接書かずzeroとsuccの組み合わせでチャーチ数を表現した場合 チャーチ数(実行時のクロージャ) ペアノ数(ヴァリアント) let zero = fun f
x -> x let succ = fun n f x -> f (n f x) three = succ (succ (succ zero)) type nat = Z | S of nat S (S (S Z)) 1 クロージャ 1 コンストラクタ fun f x -> f (n f x) n = ≅ S fun f x -> f (n f x) n = ≅ S fun f x -> f (n f x) n = ≅ S (succ が捕獲した n = 子への参照 = S of nat の中身) fun f x -> x zero(環境なし) ©2026 Wantedly, Inc. ≅ Z
チャーチのリストの実行時表現 nilとconsで表現される通常のリストと同型になる ※匿名関数を直接書かずnilとconsの組み合わせでチャーチのリストを記述した場合 チャーチリスト(実行時のクロージャ) 標準ライブラリのリスト let nil = fun f
x -> x let cons h t = fun f x -> f h (t f x) l = cons 1 (cons 2 (cons 3 nil)) [1; 2; 3] = 1 :: 2 :: 3 :: [] 1 クロージャ 1 cons セル fun f x -> f h (t f x) h = 1 t = ≅ 1 fun f x -> f h (t f x) h = 2 t = ≅ 2 fun f x -> f h (t f x) h = 3 t = ≅ 3 (h = 要素、t = 次への参照) fun f x -> x nil(環境なし) ©2026 Wantedly, Inc. ≅ []
関数もある種のデータ構造を作る ©2026 Wantedly, Inc.
λ計算とチューリングマシンの対応から関数閉包を見る 関数ポインタは状態機械に、関数閉包はテープに対応 λ計算とチューリングマシンの計算能力は等価 コンパイル時 プログラムは有限のテキスト 実行時 make_adder 1, make_adder 2,
... let make_adder z = z = 1 code z = 2 code z = 42 code fun a -> a + z ラムダ式は有限個 = 有限の制御(TM の状態表) コードは 1 つを共有 ⋮ 差分は環境だけが担う = 可変の記憶(テープ) ©2026 Wantedly, Inc.
関数閉包を積極的に作るアルゴリズムの計算量 ©2026 Wantedly, Inc.
例1: List.fold_rightでList.fold_leftを書く 関数閉包をアキュムレータで引き回すとできる 初期値は fold_right で作った関数閉包へ最後に渡してやる 実行時に、要素の数だけこのクロージャが生まれる 環境に捕獲するのは x と
g。g : 'b -> 'b = 続きの畳み込み(継続) let fold_left f z xs = List.fold_right (fun x g -> fun a -> g (f a x)) xs (fun a -> a) z 初期の継続 id(環境なし) 初期値 z は最後、出来上がった継続に流す ©2026 Wantedly, Inc.
List.fold_rightで書いたList.fold_leftの実行時の挙動 中間表現でペアノのリストが作られる スタック2つでキューを作るような挙動になるが、実行効率は良くない 継続 g の鎖(実行時のクロージャ) 入力のリスト let fold_left f
z xs = List.fold_right (fun x g -> fun a -> g (f a x)) xs (fun a -> a) z 1 クロージャ xs = [1; 2; 3] = 1 :: 2 :: 3 :: [] 1 cons セル fun a -> g (f a x) x = 1 g = ≅ 1 fun a -> g (f a x) x = 2 g = ≅ 2 fun a -> g (f a x) x = 3 g = ≅ 3 (x = 要素、g = 次への参照) fun a -> a id(環境なし) ©2026 Wantedly, Inc. ≅ []
例2: repMin 一回の走査で葉の要素を最小値で置き換えられる 遅延評価を使っている 答えの最小値 m を、計算している最中に使う data Tree =
Leaf Int | Node Tree Tree repMin :: Tree -> Tree repMin tree = t where (m, t) = replace m tree replace m (Leaf n) = (n, Leaf m) replace m (Node t1 t2) = let (m1, t1') = replace m t1 (m2, t2') = replace m t2 in (m1 `min` m2, Node t1' t2') ©2026 Wantedly, Inc.
repMinをOCamlで書く 遅延評価のサンクを関数抽象で置き換えると書ける 評価結果は一度しか使われないのでメモ化せず名前呼びで十分 type tree = Leaf of int |
Node of tree * tree let rep_min tree = let rec replace = function | Leaf n -> (n, fun m -> Leaf m) ← 環境なし | Node (t1, t2) -> let (m1, c1) = replace t1 and (m2, c2) = replace t2 in (min m1 m2, fun m -> Node (c1 m, c2 m)) in let (m, c) = replace tree in c m ©2026 Wantedly, Inc.
repMinの実行時の挙動 結局木が2回走査される 最小値を求める走査で木と同型のクロージャが作られ、関数呼び出しで再走査される 入力の木 replace が返すクロージャ c Node (Node (Leaf
3, Leaf 1), Leaf 4) let (m, c) = replace tree Node fun m -> Node(c1 m, c2 m) Node Leaf 4 ≅ fun m -> Node(c1 m, c2 m) 同じ形 Leaf 3 ©2026 Wantedly, Inc. Leaf 1 fun m -> Leaf m fun m -> Leaf m fun m -> Leaf m
計算可能性の制約を使った面白いプログラム ©2026 Wantedly, Inc.
計算可能性の制約を使った面白いプログラム 実は (int→bool)→int 同士の等価性は決定可能 ※引数は純粋関数である必要がある type cantor = int ->
bool ← 入力は無限のビット列 type bs = Cons of bool * bs Lazy.t let rec nth (l : bs Lazy.t) n = ← 遅延ビット列(探索結果の置き場) ← 補助(ビット列の読み書き) let Cons (b, t) = Lazy.force l in if n = 0 then b else nth t (n - 1) let cantor_of l : cantor = fun n -> nth l n let cons b (a : cantor) : cantor = fun n -> if n = 0 then b else a (n - 1) let rec find_s (p : cantor -> bool) : bs Lazy.t = lazy ( ← 頭も含めて遅延(停止性の要) let b = forsome (fun a -> p (cons true a)) in Cons (b, find_s (fun a -> p (cons b a)))) and forsome (p : cantor -> bool) : bool = p (cantor_of (find_s p)) ↑ 見つけて、確かめる let forevery p = not (forsome (fun a -> not (p a))) let equal f g = forevery (fun a -> f a = g a) ©2026 Wantedly, Inc. ← De Morgan
(int→bool)→int の等価性を試す # let f a = if a 3
then 10 else if a 7 then 20 else 30;; val f : (int -> bool) -> int = <fun> # let h a = if a 7 then (if a 3 then 10 else 20) else (if a 3 then 10 else 30);; val h : (int -> bool) -> int = <fun> # let k a = if a 3 then 11 else 30;; val k : (int -> bool) -> int = <fun> # equal f h;; - : bool = true ← 外延は同じ・形は違う 2 つが、等しいと判定された # equal h k;; # equal k f;; - : bool = false - : bool = false (k は bit 3 のとき 11 を返すので、f とも h とも等しくない) ©2026 Wantedly, Inc.
表示的意味論からの正当化 (1/2) 計算機上で書ける純粋関数は連続になる プログラムの領域 D が D ≅ (D →
D) に閉じている必要がある ✕ D ≅ (D → D) ◯ D ≅ [D → D] |D → D| > |D|(Cantor) 連続関数に制限する(Scott 1969) 集合論的な関数 D → D 連続関数 = 有限近似で決まる 計算可能な関数 (機械は入力を有限しか観察できない) 計算可能 ©2026 Wantedly, Inc. 連続: 制限しても、はみ出すものはない
表示的意味論からの正当化 (2/2) int→bool はカントール空間でありコンパクト 入力 a : int -> bool
= 無限のビット列(この埋め方の全体 = カントール空間) f a = if a 3 then 10 else if a 7 then 20 else 30 0 1 2 3 4 5 6 7 8 9 ? ? ? ? ? ? ? ? ? ? f が読むのは有限個だけ(計算可能 … (無限に続く) 連続) その位置には全入力共通の上限がある(コンパクト 一様) a 3 = true a 3 = F, a 7 = true a 3 = F, a 7 = false f a = 10 f a = 20 f a = 30 非可算個の入力が、有限個のケースに割れる (このケースを比べ尽くせば equal は終わる = 有限時間の全数探索) ©2026 Wantedly, Inc.
まとめ ©2026 Wantedly, Inc.
まとめ 1. ある種の関数はデータ構造に対応する 2. 見えにくいが、逆に関数もデータ構造に対応する • 油断すると実行時のオーバーヘッドになる 3. 計算機の表現できる関数は意外と狭い •
計算可能な関数しか表現できない事を利用すると面白い事ができる ©2026 Wantedly, Inc.