Slide 1

Slide 1 text

Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 − #関数型まつり 2026 — @Guvalif (TAKASE Kazuyuki)

Slide 2

Slide 2 text

自己紹介 - 高瀬 和之 (TAKASE Kazuyuki) 𝕏:@Guvalif 余談) ScalaMatsuri 2020 ぶりの登壇です 💪 Profile { works = [ "IoT エンジニア", "フロントエンド・エンジニア", "開発人事", "TechPM (← 現職)", "エンジニア育成 (← 複業)" ], memo = "関数型 XXX を名乗りがち 😗" }

Slide 3

Slide 3 text

関数型プログラミングに対する私の立ち位置 🧑‍🏫 良い設計を発見する ための、ベース知識として用いる 安全な開発を実現する ための、勘所として用いる これらは決してプログラミング言語に依存すること無く、 普遍的に応用可能 だと考える

Slide 4

Slide 4 text

アイスブレイク:"Parametricity",知ってる?

Slide 5

Slide 5 text

アイスブレイク:"Parametricity",知ってる? 初めて聞く 👂

Slide 6

Slide 6 text

アイスブレイク:"Parametricity",知ってる? 初めて聞く 👂 聞いたことはあるが、中身は知らない 🤔

Slide 7

Slide 7 text

アイスブレイク:"Parametricity",知ってる? 初めて聞く 👂 聞いたことはあるが、中身は知らない 🤔 理論的背景も含めて知っている ✌️

Slide 8

Slide 8 text

アイスブレイク:"Parametricity",知ってる? 初めて聞く 👂 聞いたことはあるが、中身は知らない 🤔 理論的背景も含めて知っている ✌️ 住んでいる 🏙️

Slide 9

Slide 9 text

アイスブレイク:"Parametricity",知ってる? 初めて聞く 👂 聞いたことはあるが、中身は知らない 🤔 理論的背景も含めて知っている ✌️ 住んでいる 🏙️

Slide 10

Slide 10 text

I. (パラメトリック) 多相型

Slide 11

Slide 11 text

多相型のモチベーション (1) 配列に対する head 関数を考える もし 多相型が無い 場合、次のようなことが起こる: const headN: (_: number[]) => number | undefined = (xs) => xs.at(0); const headS: (_: string[]) => string | undefined = (xs) => xs.at(0); const headB: (_: boolean[]) => boolean | undefined = (xs) => xs.at(0); // 以下、同一な実装であっても各型ごとに区別しなければならない 😇

Slide 12

Slide 12 text

多相型のモチベーション (2) 多相型がある 場合、次のように記述できる: const head: (_: T[]) => T | undefined = (xs) => xs.at(0); head([ 1, 2, 3 ]); // 1 head([ 'a', 'b', 'c' ]); // 'a' head([ true, false, true ]); // true head([]); // undefined // 任意の型 `T` に対して、(型安全性を保って) 同一な実装を用いることができる 🙆‍♂️

Slide 13

Slide 13 text

本当に? 🤔 ある型 T ごとに分岐を許すと、変な実装も許されそう しかし直感的には、そのような実装はできないようにしたい 多相型で型付けされた実装 に対して、 暗黙のうちに ある型 T に依存しない ことを考えていそう → 多相型で型付けすることで、実装が限定される ことを導きたい

Slide 14

Slide 14 text

II. 数学的なモデル化

Slide 15

Slide 15 text

前提 本資料では、以下の前提のもと数学的なモデルを考えていく: (素朴な) 型 を 集合 とみなす 純粋な関数のみを考慮する 不動点演算子 (いわゆる Y or Z コンビネータ) は考慮しない type F = (_: (_: X) => Y) => (_: X) => Y; type G = (_: G ) => (_: X) => Y; const Z = (f: F) => ( (g: G) => f((x) => g(g)(x)) ) ( (g: G) => f((x) => g(g)(x)) );

Slide 16

Slide 16 text

導入:多相型の表現 多相型で型付けされた値は (チルダ) で区別する。このとき: 1. 通常の TypeScript における型表現 ∗ ~ ​ ​ ​ ​ h ~ h ~ ​ h ~ A : : : ⟨T⟩(_ : T[]) ⇒ T ∣ undefined ⟨T⟩. T[] ⇒ T ∣ undefined ⟨A/T⟩. A[] ⇒ A ∣ undefined (1) (2) (3)

Slide 17

Slide 17 text

導入:多相型の表現 多相型で型付けされた値は (チルダ) で区別する。このとき: 1. 通常の TypeScript における型表現 2. 引数を省力した型表現 (本資料では一貫してこの型表現を採用) ∗ ~ ​ ​ ​ ​ h ~ h ~ ​ h ~ A : : : ⟨T⟩(_ : T[]) ⇒ T ∣ undefined ⟨T⟩. T[] ⇒ T ∣ undefined ⟨A/T⟩. A[] ⇒ A ∣ undefined (1) (2) (3)

Slide 18

Slide 18 text

導入:多相型の表現 多相型で型付けされた値は (チルダ) で区別する。このとき: 2. 引数を省力した型表現 (本資料では一貫してこの型表現を採用) 3. ある型 A による具体化 ∗ ~ ​ ​ ​ ​ h ~ h ~ ​ h ~ A : : : ⟨T⟩(_ : T[]) ⇒ T ∣ undefined ⟨T⟩. T[] ⇒ T ∣ undefined ⟨A/T⟩. A[] ⇒ A ∣ undefined (1) (2) (3) ※ ※ 厳密には、具体化した時点で型パラメータ は消去されます ( は視覚的区別 )

Slide 19

Slide 19 text

検討:多相型を 集合 でモデル化する? 🤔 型を集合とみなすことは素朴だが、(e.g. boolean = ) ある型 T ごとに分岐する実装 を排除しきれない! {true, false}

Slide 20

Slide 20 text

検討:多相型を 集合 でモデル化する? 🤔 型を集合とみなすことは素朴だが、(e.g. boolean = ) ある型 T ごとに分岐する実装 を排除しきれない! e.g. を考える: 型パラメータ が取れること を、 宇宙 に属する 任意の集合 に対する操作 として解釈する 関数の型 を、配置集合 として解釈する ここで、ある型 による具体化 は、恒等関数以外も含みうる {true, false} ⟨T⟩. T ⇒ T ⟨T⟩ U T T ⇒ T TT A AA

Slide 21

Slide 21 text

方針:多相型を 関係 でモデル化し、制約を強める そもそも "関係" とは? デカルト積 の部分集合 のこと ソフトウェア・エンジニア的には、 2 Tuple の集まりのこと A × B

Slide 22

Slide 22 text

方針:多相型を 関係 でモデル化し、制約を強める そもそも "関係" とは? デカルト積 の部分集合 のこと ソフトウェア・エンジニア的には、 2 Tuple の集まりのこと 本資料では、関係を考えるとき で囲って表す は、 の部分集合であることを表す A × B [[ X ]] : (A, B) ​ R [[ ]] (A, B) ​ R A × B

Slide 23

Slide 23 text

III. さまざまな関係

Slide 24

Slide 24 text

空関係 の部分集合として、空集合 を取ることができる これも として、関係に持ち上げて捉えて良い A × B ∅ [[ ∅ ]] [[ ∅ ]] : (A, B) ​ R

Slide 25

Slide 25 text

恒等関係 型を関係に持ち上げる際の、自明な例のひとつ: [[ I ​ ]] : T (T, T) ​ = R {(t, t) ∣ t ∈ T} ≅ T

Slide 26

Slide 26 text

恒等関係 型を関係に持ち上げる際の、自明な例のひとつ: e.g. の持ち上げ: [[ I ​ ]] : T (T, T) ​ = R {(t, t) ∣ t ∈ T} ≅ T boolean ​ ​ ​ [[ I ​ ]] boolean = = = ≅ {(t, t) ∣ t ∈ boolean} {(t, t) ∣ t ∈ {true, false}} {(true, true), (false, false)} boolean

Slide 27

Slide 27 text

恒等関係 型を関係に持ち上げる際の、自明な例のひとつ: e.g. の持ち上げ: [[ I ​ ]] : T (T, T) ​ = R {(t, t) ∣ t ∈ T} ≅ T boolean ​ ​ ​ [[ I ​ ]] boolean = = = ≅ {(t, t) ∣ t ∈ boolean} {(t, t) ∣ t ∈ {true, false}} {(true, true), (false, false)} boolean

Slide 28

Slide 28 text

恒等関係 型を関係に持ち上げる際の、自明な例のひとつ: e.g. の持ち上げ: [[ I ​ ]] : T (T, T) ​ = R {(t, t) ∣ t ∈ T} ≅ T boolean ​ ​ ​ [[ I ​ ]] boolean = = = ≅ {(t, t) ∣ t ∈ boolean} {(t, t) ∣ t ∈ {true, false}} {(true, true), (false, false)} boolean

Slide 29

Slide 29 text

恒等関係 型を関係に持ち上げる際の、自明な例のひとつ: e.g. の持ち上げ: [[ I ​ ]] : T (T, T) ​ = R {(t, t) ∣ t ∈ T} ≅ T boolean ​ ​ ​ [[ I ​ ]] boolean = = = ≅ {(t, t) ∣ t ∈ boolean} {(t, t) ∣ t ∈ {true, false}} {(true, true), (false, false)} boolean

Slide 30

Slide 30 text

関係としての関数 関数 は、関係 に持ち上げることができる: f : X ⇒ Y [[ f ]] [[ f ]] : (X, Y) ​ = R {(x, ​ ) ∣ ∈Y ​ f(x) x ∈ X}

Slide 31

Slide 31 text

関係としての関数 関数 は、関係 に持ち上げることができる: e.g. not 関数 の持ち上げ: f : X ⇒ Y [[ f ]] [[ f ]] : (X, Y) ​ = R {(x, ​ ) ∣ ∈Y ​ f(x) x ∈ X} ¬ : boolean ⇒ boolean ​ ​ ​ [[ ¬ ]] = = = {(x, ¬(x)) ∣ x ∈ boolean} {(x, ¬(x)) ∣ x ∈ {true, false}} {(true, false), (false, true)}

Slide 32

Slide 32 text

関係としての関数 関数 は、関係 に持ち上げることができる: e.g. not 関数 の持ち上げ: f : X ⇒ Y [[ f ]] [[ f ]] : (X, Y) ​ = R {(x, ​ ) ∣ ∈Y ​ f(x) x ∈ X} ¬ : boolean ⇒ boolean ​ ​ ​ [[ ¬ ]] = = = {(x, ¬(x)) ∣ x ∈ boolean} {(x, ¬(x)) ∣ x ∈ {true, false}} {(true, false), (false, true)}

Slide 33

Slide 33 text

関係としての関数 関数 は、関係 に持ち上げることができる: e.g. not 関数 の持ち上げ: f : X ⇒ Y [[ f ]] [[ f ]] : (X, Y) ​ = R {(x, ​ ) ∣ ∈Y ​ f(x) x ∈ X} ¬ : boolean ⇒ boolean ​ ​ ​ [[ ¬ ]] = = = {(x, ¬(x)) ∣ x ∈ boolean} {(x, ¬(x)) ∣ x ∈ {true, false}} {(true, false), (false, true)}

Slide 34

Slide 34 text

メモ 📝:関係の表現力 関数 の関係への持ち上げ は、 1 つの入力に対して 1 つの出力を持つ表現 に限定される 一方、 関係 は の任意の部分集合なので、 1 つの入力に対して複数の出力を持つ表現 も許容できる f : X ⇒ Y [[ f ]] X × Y

Slide 35

Slide 35 text

メモ 📝:関係の表現力 関数 の関係への持ち上げ は、 1 つの入力に対して 1 つの出力を持つ表現 に限定される 一方、 関係 は の任意の部分集合なので、 1 つの入力に対して複数の出力を持つ表現 も許容できる e.g. 平方根の関係 について: f : X ⇒ Y [[ f ]] X × Y [[ S ]] = {(x, y) ∣ x = y } 2 (4, 2) ∈ [[ S ]] ∧ (4, −2) ∈ [[ S ]]

Slide 36

Slide 36 text

関数関係 (1) 2 つの関係 と を用いて、 2 Tuple の各要素が関数 となるような関係を定義できる: [[ X ]] : (X, X ) ​ ′ R [[ Y ]] : (Y, Y ) ​ ′ R [[ X ]] ​ R [[ Y ]] : (X ⇒ Y, X ⇒ Y ) ​ ′ ′ R (f, f ) ​ ​ ​ ​ { ′ for all (x, x ) ′ (f(x), f (x )) ′ ′ ∈ ∈ [[ X ]], [[ Y ]] }

Slide 37

Slide 37 text

関数関係 (2) 具体例として、 を考えてみる: 【 関数関係が満たすべき条件 】 [[ I ​ ]] ​ boolean R [[ I ​ ]] 0∣1 ​ ​ ​ ​ for all ( ​ ) x=x′ ※ x, x′ ( ​ ) f(x)=f (x ) ′ ′ ※ ​ f(x), f (x ) ′ ′ ∈ ∈ [[ I ​ ]], boolean [[ I ​ ]] 0∣1 ※ 恒等関係に含まれる 2 Tuple は、常に第 1 要素と第 2 要素が等しいため

Slide 38

Slide 38 text

関数関係 (2) 具体例として、 を考えてみる: 【 関数関係が満たすべき条件 】 → 関数の外延性から、 を満たす 2 Tuple のみ考えれば良い [[ I ​ ]] ​ boolean R [[ I ​ ]] 0∣1 ​ ​ ​ ​ for all ( ​ ) x=x′ ※ x, x′ ( ​ ) f(x)=f (x ) ′ ′ ※ ​ f(x), f (x ) ′ ′ ∈ ∈ [[ I ​ ]], boolean [[ I ​ ]] 0∣1 f = f′ ※ 恒等関係に含まれる 2 Tuple は、常に第 1 要素と第 2 要素が等しいため

Slide 39

Slide 39 text

関数関係 (3) その上で、 関数の型 の値 をすべて列挙する: boolean ⇒ 0∣1 const c0: (_: boolean) => 0|1 = (_) => 0; const c1: (_: boolean) => 0|1 = (_) => 1; const n: (_: boolean) => 0|1 = (x) => Number(x) as 0|1; const u: (_: boolean) => 0|1 = (x) => Number(!x) as 0|1;

Slide 40

Slide 40 text

関数関係 (4) 最後に を満たす 2 Tuple を列挙すると、以下となる: f = f′ [[ I ​ ]] ​ boolean R [[ I ​ ]] = 0∣1 {(c ​ , c ​ ), (c ​ , c ​ ), (n, n), (u, u)} 0 0 1 1

Slide 41

Slide 41 text

全称関係 (1) を、関係 を表現のどこかに持つ関係とする その上で、関係 について 全称量化 することを考える: F([[ X ]]) [[ X ]] [[ X ]] ⟨[[ X ]]⟩. F([[ X ]]) = ( ​ , ​ ) ​ ​ ​ ​ { f ~ f ~′ for all [[ X ]] ( ​ ​ , ​ ​ ) f ~ X f ~′ X′ : ∈ (X, X ) ​ , ′ R F([[ X ]]) }

Slide 42

Slide 42 text

全称関係 (1) を、関係 を表現のどこかに持つ関係とする その上で、関係 について 全称量化 することを考える: ここで、 は で添字づけられた集まり, は で添字づけられた集まりを意味し、 と を型で考えると、 多相型で型付けされた値 とみなせる F([[ X ]]) [[ X ]] [[ X ]] ⟨[[ X ]]⟩. F([[ X ]]) = ( ​ , ​ ) ​ ​ ​ ​ { f ~ f ~′ for all [[ X ]] ( ​ ​ , ​ ​ ) f ~ X f ~′ X′ : ∈ (X, X ) ​ , ′ R F([[ X ]]) } ​ f ~ X ​ f ~′ X′ X X′

Slide 43

Slide 43 text

全称関係 (2) 具体例として、 を考えてみる: 【 全称関係が満たすべき条件 】 ⟨[[ X ]]⟩. [[ X ]] ​ ​ ​ ​ for all [[ X ]] ( ​ ​ , ​ ​ ) f ~ X f ~′ X′ : ∈ (X, X ) ​ , ′ R [[ X ]]

Slide 44

Slide 44 text

全称関係 (2) 具体例として、 を考えてみる: 【 全称関係が満たすべき条件 】 ここで、どのような と に対しても、 空関係 を考慮する必要がある → 述語を満たせない 😇 ⟨[[ X ]]⟩. [[ X ]] ​ ​ ​ ​ for all [[ X ]] ( ​ ​ , ​ ​ ) f ~ X f ~′ X′ : ∈ (X, X ) ​ , ′ R [[ X ]] X X′ [[ ∅ ]] : (X, X ) ​ ′ R

Slide 45

Slide 45 text

全称関係 (2) 具体例として、 を考えてみる: 【 全称関係が満たすべき条件 】 ここで、どのような と に対しても、 空関係 を考慮する必要がある → 述語を満たせない 😇 → を満たすことは、とても大変 😵‍💫 ⟨[[ X ]]⟩. [[ X ]] ​ ​ ​ ​ for all [[ X ]] ( ​ ​ , ​ ​ ) f ~ X f ~′ X′ : ∈ (X, X ) ​ , ′ R [[ X ]] X X′ [[ ∅ ]] : (X, X ) ​ ′ R for all [[ ∗ ]]

Slide 46

Slide 46 text

ここまでのまとめ 以下それぞれを定義し、簡単に性質を確かめた: 空関係 恒等関係 関係としての関数 関数関係 全称関係 (本資料では取り扱わないが) 参考文献では 直積関係 や リスト関係 なども記載されているので、興味があれば参照まで 📝 [[ ∅ ]] [[ I ​ ]] T [[ f ]] [[ X ]] ​ R [[ Y ]] ⟨[[ X ]]⟩. F([[ X ]])

Slide 47

Slide 47 text

※ まだ、実装が限定される性質は示していない 🤔

Slide 48

Slide 48 text

IV. "Parametricity" の主張

Slide 49

Slide 49 text

Parametricity 多相型を持つ型システムを考える ある値 の型 から、帰納的に導出できる 関係 は、 を満たす 【 簡単な具体例 】 に関して、 が成り立つ ※ t T [[ T ]] (t, t) ∈ [[ T ]] ​ : t ​ true ​ T ​ boolean (true, true) ∈ [[ I ​ ]] boolean ※ 参考文献における記述は "閉じた項" ですが、型環境を適切に考慮すれば解消可能です

Slide 50

Slide 50 text

実際に試してみる (1) (の型) から、 という関係を 帰納的に導出した上で、満たすべき条件を考える: 【 関係が満たすべき条件 】 ​ : f ~ ⟨T⟩. T ⇒ T ⟨[[ T ]]⟩. [[ T ]] ​ R [[ T ]] ​ ​ ​ ​ for all for all [[ T ]] (t, t ) ′ ( ​ ​ (t), ​ ​ (t )) f ~ T f ~ T′ ′ : ∈ ∈ (T, T ) ​ , ′ R [[ T ]], [[ T ]]

Slide 51

Slide 51 text

実際に試してみる (1) (の型) から、 という関係を 帰納的に導出した上で、満たすべき条件を考える: 【 関係が満たすべき条件 】 ​ : f ~ ⟨T⟩. T ⇒ T ⟨[[ T ]]⟩. [[ T ]] ​ R [[ T ]] ​ ​ ​ ​ for all for all [[ T ]] (t, t ) ′ ( ​ ​ (t), ​ ​ (t )) f ~ T f ~ T′ ′ : ∈ ∈ (T, T ) ​ , ′ R [[ T ]], [[ T ]]

Slide 52

Slide 52 text

実際に試してみる (1) (の型) から、 という関係を 帰納的に導出した上で、満たすべき条件を考える: 【 関係が満たすべき条件 】 ​ : f ~ ⟨T⟩. T ⇒ T ⟨[[ T ]]⟩. [[ T ]] ​ R [[ T ]] ​ ​ ​ ​ for all for all [[ T ]] (t, t ) ′ ( ​ ​ (t), ​ ​ (t )) f ~ T f ~ T′ ′ : ∈ ∈ (T, T ) ​ , ′ R [[ T ]], [[ T ]]

Slide 53

Slide 53 text

実際に試してみる (2) の部分集合として、関数の持ち上げ を 任意にとってみる: (T, T ) ​ ′ R [[ g : T ⇒ T ]] ′ ​ ​ ​ ​ for all for all [[ g ]] (t, t ) ′ ( ​ ​ (t), ​ ​ (t )) f ~ T f ~ T′ ′ : ∈ ∈ (T, T ) ​ , ′ R [[ g ]], [[ g ]]

Slide 54

Slide 54 text

実際に試してみる (3) 関数の持ち上げ は、 を満たす 2 Tuple のみ持つので: [[ g ]] (∗, g(∗)) ​ ​ ​ ​ for all for all [[ g ]] (t, ​ ) g(t) ​ t′ ( ​ ​ (t), ​ ) f ~ T g( ​ ​ (t)) f ~ T ​ ​ ​ (t ) f ~ T′ ′ : ∈ ∈ (T, T ) ​ , ′ R [[ g ]], [[ g ]]

Slide 55

Slide 55 text

実際に試してみる (4) ここまでの状況を整理すると: ​ ​ ​ t′ ​ ​ (t ) f ~ T′ ′ = = g(t) g( ​ ​ (t)) f ~ T

Slide 56

Slide 56 text

実際に試してみる (4) ここまでの状況を整理すると: 代入して整理すると、以下の等式が得られる: ​ ​ ​ t′ ​ ​ (t ) f ~ T′ ′ = = g(t) g( ​ ​ (t)) f ~ T ​ ​ (g(t)) = f ~ T′ g( ​ ​ (t)) f ~ T

Slide 57

Slide 57 text

実際に試してみる (4) ここまでの状況を整理すると: 代入して整理すると、以下の等式が得られる: → この等式によって、 の実装が限定される! ​ ​ ​ t′ ​ ​ (t ) f ~ T′ ′ = = g(t) g( ​ ​ (t)) f ~ T ​ ​ (g(t)) = f ~ T′ g( ​ ​ (t)) f ~ T ​ f ~

Slide 58

Slide 58 text

Fin. 🥳

Slide 59

Slide 59 text

α. 自然性条件

Slide 60

Slide 60 text

関数関係,ふたたび (1) 2 つの関係 と を用いて、 2 Tuple の各要素が関数となるような関係を定義できる: [[ X ]] : (X, X ) ​ ′ R [[ Y ]] : (Y, Y ) ​ ′ R [[ X ]] ​ R [[ Y ]] : (X ⇒ Y, X ⇒ Y ) ​ ′ ′ R (f, f ) ​ ​ ​ ​ { ′ for all (x, x ) ′ (f(x), f (x )) ′ ′ ∈ ∈ [[ X ]], [[ Y ]] }

Slide 61

Slide 61 text

関数関係,ふたたび (2) 2 つの関係 と を取り巻く状況: [[ X ]] : (X, X ) ​ ′ R [[ Y ]] : (Y, Y ) ​ ′ R

Slide 62

Slide 62 text

関数関係,ふたたび (3) から関数の持ち上げ を、 から関数の持ち上げ を選ぶ: (X, X ) ​ ′ R [[ g ]] (Y, Y ) ​ ′ R [[ h ]]

Slide 63

Slide 63 text

関数関係,ふたたび (3) から関数の持ち上げ を、 から関数の持ち上げ を選ぶ: → \完全に可換図式/ (X, X ) ​ ′ R [[ g ]] (Y, Y ) ​ ′ R [[ h ]]

Slide 64

Slide 64 text

全称関係で "対象" を任意に動かす 可換図式が任意に成立することを表し、 特に の場合は 自然変換 といえる ​ = f ~ ​ f ~′

Slide 65

Slide 65 text

まとめ 関数関係 により、 可換図式 が得られる 全称関係 により、 自然変換 が得られる これより、 多相関数は自然変換 であることもわかる 【 参考文献 】 『Theorems for free !』by Philip Wadler 『型システム入門 - プログラミング言語と型の理論 -』by オーム社