Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

梶川 琢馬 𝕏 @kajitack 株式会社 TechBowl VPoT TechTrain の開発 / メンター 普段は PHP や TypeScript で web アプリケーション開発 先月、オーストラリアのトライアスロンの大会に行ってました。 関数型まつりは初参加!コアスタッフもやってます! スライドは X で公開します x.com/kajitack 2/41

Slide 3

Slide 3 text

3/41

Slide 4

Slide 4 text

TechTrain は関数型まつりの PR スポンサーです TechTrain Media のインタビュー記事で、関数型まつり 2026 を紹介しています 初心者か実務経験者かで、聴くべきセッションは違う 今日の残りのセッション選びにそのまま使えます techtrain.dev/media/articles/9rtggtxrgl 座長 5 人が語る、このまつりに込めた思い 読んでから聴くと、セッションの見え方が変わります techtrain.dev/media/articles/pq682joc35i 4/41

Slide 5

Slide 5 text

前提とゴール 前提 普段は関数型言語以外で web アプリケーションを開発している方 型理論や証明が、なぜ「関数型」の文脈で 語られるのかピンと来ていない方 ゴール 関数型プログラミング、型、証明のつながりを知る 5/41

Slide 6

Slide 6 text

関数型プログラミングとは 関数の適用と合成を、計算の基本にするプログラミングのスタイル 実務の目線で言い換えると、副作用(隠れた入力と隠れた出力)を関数から減らし、 入力から出力を作るだけの純粋な関数でロジックを組むこと Bird & Wadler "Introduction to Functional Programming" (1988) Kris Jenkins "What Is Functional Programming?" (2015) https://blog.jenkster.com/2015/12/what-is-functional-programming.html 6/41

Slide 7

Slide 7 text

関数型と命令型 命令型は「これをやれ、次にこれをやれ」という手順の列で、状態を書き換えながら進む 関数型は「値から値への変換」を組み合わせた、ひとつの式 for 文で合計を作るのは手順の列、畳み込みで合計を作るのはひとつの式 naoya「関数型プログラミングと型システムのメンタルモデル」 7/41

Slide 8

Slide 8 text

関数型プログラミング言語の特徴 副作用を避けるという方針が、言語の作りに現れている 値は書き換えず新しく作る(イミュータブル)、関数を値として渡し合成する(第一級関数) 型には 2 つの流派がある 静的型付けの Haskell、OCaml、Scala。動的型付けの Clojure、Elixir 今日は、型を強く使う流派の話 8/41

Slide 9

Slide 9 text

web アプリと IO 仕事の多くは、外界とのやりとり(IO) IO → 計算(業務ロジック)→ IO naoya「関数型プログラミングと型システムのメンタルモデル」https://speakerdeck.com/naoya/guan-shu-xing- puroguramingutoxing-sisutemunomentarumoderu 図: Scott Wlaschin "Reinventing the Transaction Script" (NDC London 2020) https://www.slideshare.net/ScottWlaschin/reinve the-transaction-script-ndc-london-2020 9/41

Slide 10

Slide 10 text

ドメインロジックをIOから分離したい ドメインエキスパートと開発者が、同じ言葉(ユビキタス言語)で業務のモデルを作る そのモデルをコードに直結させ、仕様からコードへの「翻訳」で生まれる歪みをなくす 業務ルールが変わったとき、コードのどこを直すべきかがモデルから直感的にわかる Eric Evans "Domain-Driven Design: Tackling Complexity in the Heart of Software" (2003) 10/41

Slide 11

Slide 11 text

関数型は、ドメインモデリングの 武器になる 代数的データ型、不変性、純粋関数 関数型の道具は、DDD の目標にそのまま効く 業務の言葉で型を書けば、設計とコードのズレは型エラーになる 不正な状態は型で表現させず、失敗は Result で網羅する 不変性で値を再現し、I/O を端に寄せてコアを純粋に保つ Scott Wlaschin『関数型ドメインモデリング ドメイン駆動設計とF#でソフトウェアの複雑さに立ち向かおう』(猪股健太郎 訳、アスキードワンゴ、2024) 11/41

Slide 12

Slide 12 text

型と副作用 型が語るのは「OrderInput を受け取り、Order を返す」ここまで 隠れた入力: DB 接続、メールサーバ、現在時刻 隠れた出力: DB の行、送信メール、ログ、例外 隠れた入力と、隠れた出力。型はそのどちらも語らない function placeOrder(input: OrderInput): Order { const order = Order.create(input); repository.save(order); // DBに書き込む mailer.sendConfirmation(order); // メールを送る logger.info("order placed"); // ログを書く return order; } TypeScript 12/41

Slide 13

Slide 13 text

副作用を分離 決める(純粋)と書く(副作用)に分ける。「決める」はモックなしでテストできる // 決める: 入力から「何が起きたか」を作る純粋な関数 function decide(input: OrderInput, now: Date): OrderPlaced { const order = Order.create(input, now); return { order, events: [{ type: "OrderPlaced", orderId: order.id }] }; } // 書く: 決めた結果を解釈して I/O を実行する async function placeOrder(input: OrderInput): Promise { const { order, events } = decide(input, clock.now()); await repository.save(order); await publisher.publish(events); // メールとログは購読側へ return order; } TypeScript 13/41

Slide 14

Slide 14 text

副作用の分離で、得たいもの テストがしやすくなる。部品を差し替えられる それはそう。でも、副次的なもの 主目的は、業務ロジックを計算機への命令ではなく 純粋な「計算」として考えられるようにすること naoya「関数型プログラミングと型システムのメンタルモデル」https://speakerdeck.com/naoya/guan-shu-xing-puroguramingutoxing-sisutemunomentarumoderu 14/41

Slide 15

Slide 15 text

step 1 副作用の分離は、 なぜ型の信頼性を高めるのか ラムダ計算を起点に、関数型と型システムの成り立ちを辿る 15/41

Slide 16

Slide 16 text

関数型の始まりはラムダ計算 λx. x + 1 「x を受け取って x + 1 を返す」 1930 年代に Church が定義した計算モデル 関数の定義と適用、それだけで全ての計算を表現できる 関数型プログラミングの数学的な基盤 Alonzo Church, "An Unsolvable Problem of Elementary Number Theory" (1936) https://doi.org/10.2307/2371045 16/41

Slide 17

Slide 17 text

参照透過性 式を評価結果で置き換えても、プログラムの意味が変わらない ラムダ計算では自然に成り立つ(状態や副作用という概念がない) 状態と副作用があると、式と値の対応ができない f x = x + 4 -- f 3 は常に 7 -- コード中の f 3 は、すべて 7 に置き換えてよい Haskell 17/41

Slide 18

Slide 18 text

入力から出力を作る。それ以外の意味が存在しない A -> B は「A を受け取って B を返す関数」の型 隠れた DB 書き込みも、握りつぶされる例外もない シグネチャを読む = 関数の影響範囲を全て知る parse :: String -> Maybe Config -- Maybe Config = Config か「なし」 Haskell 18/41

Slide 19

Slide 19 text

型付きラムダ計算 λ(x:Int). x + 1 : Int → Int ラムダ計算に型を付けると、型の合わない式を機械的に排除できる。この検査が型検査 型検査、型推論、代数的データ型。いま使っている型システムの原型 19/41

Slide 20

Slide 20 text

型検査は、何を約束しているのか 「正しく型付けされた式は、行き詰まらない」「評価を進めても、型は変わらない」 この 2 つの定理が「型が付いたプログラムは、ある種のエラーを起こさない」を保証する 型は雰囲気ではなく、証明された保証 Robin Milner "A Theory of Type Polymorphism in Programming" (1978) https://doi.org/10.1016/0022-0000(78)90014-4 型健全性の統語的手法は Wright & Felleisen (1994)、Progress / Preservation の整理は Harper 20/41

Slide 21

Slide 21 text

ラムダ計算 (1930s) 関数の定義と適⽤だけ の計算モデル 関数型プログラミング 純粋関数、参照透過性 型付きラムダ計算 型システム 型検査、型推論、ADT 「FP 言語だから型が強い」のではない。どちらもラムダ計算から生まれ、一緒に発展してきた 21/41

Slide 22

Slide 22 text

step 2 型が強くなると、 なぜ「証明」の話が出てくるのか 型を命題として読む対応関係と、副作用がそれを壊す仕組み 22/41

Slide 23

Slide 23 text

Curry-Howard対応 型 = 命題 プログラム = 証明 命題とは「A ならば B」のような、真偽が決まる主張のこと 証明とは、決まった規則だけで命題を導いた手順のこと。手順だから、機械的に検査できる λ(x:A). x : A → A 「A を受け取ってそのまま返す関数」は、「A を仮定すると A が成り立つ」という証明と 同じ形 引数を受け取ることが仮定を置くことに、値を返すことが結論を導くことに対応する Philip Wadler, "Propositions as Types" (2015) https://homepages.inf.ed.ac.uk/wadler/papers/propositions-as-types/propositions-as-types.pdf 23/41

Slide 24

Slide 24 text

型と命題の対応 型(プログラミング) 命題(論理学) 型 A -> B 「A ならば B」 直積型 (A, B) 「A かつ B」 直和型 Either A B (どちらか一方) 「A または B」 その型の値を実際に作れる 命題を証明できる 24/41

Slide 25

Slide 25 text

プログラムを書くことによって証明ができる 書けたこと自体が命題の証明になる 値を作れること = 証明できること -- 命題「A かつ B ならば A」 theorem fst {A B : Prop} (h : A ∧ B) : A := h.left -- A かつ B から、A を取り出す 25/41

Slide 26

Slide 26 text

では、副作用があると? どれも型は A -> B (A ならば B の証明)を名乗るのに、B の値を作らずに型検査を通る これが「偽の証明」。偽の証明が書ける体系では、どんな命題でも証明できてしまう 対応は、証明としての信用を失う B f(A a) { launchMissiles(); return null; } // 副作用 + null B g(A a) { while (true) {} } // 停止しない B h(A a) { throw new Error(); } // 例外 26/41

Slide 27

Slide 27 text

だからFP言語は、副作用を型で管理する 問題 対処 言語の例 副作用 IO 型で明示 Haskell 例外、null Maybe / Result で型に表現 Haskell、Rust 停止しない 全域関数を強制 Lean、Agda(定理証明のための言語) IO String は「実行すると文字列を得る手順書」。組み立ては純粋なまま、実行を端に寄せる 「Haskell に副作用がない」のではなく、型で管理している 27/41

Slide 28

Slide 28 text

証明の力は、2 つの軸で決まる 検査が証明として信用できるかは、純粋性と全域性で決まる。 もうひとつの軸が、型の表現力。どこまでの命題を型として語れるか ここまで証明できたのは「A かつ B ならば A」のような、型の間の関係まで 「ソート済みである」「長さが 1 以上」のような、値についての命題はまだ型に書けない 28/41

Slide 29

Slide 29 text

証明における型のメンタルモデル 集合として見る 型は、値の集まり Int 型は整数の集合 String 型は文字列の集合 基本的な理解 命題として見る 型は、証明すべき主張 A -> B は「A ならば B」 値を作れること = 証明できること Curry-Howard 対応 29/41

Slide 30

Slide 30 text

表現できる命題の範囲を広げると証明支援系 List Int は長さが分からない。 Vec 3 Int は長さがちょうど 3 だと型が保証する 先頭要素を返す head の型が「長さ 1 以上」を要求すると、空リストへの head は実行前に 型エラーになる 型が「値」に依存できると、幅広い命題が型として書ける プログラムが仕様を満たすことを数学的に証明する世界が形式検証 形式検証をおこなう Lean、Agda、Coq など 30/41

Slide 31

Slide 31 text

証明のメリット 型検査は、言語が用意した命題まで。証明は、命題を自分で書ける 「どのポリシーも許可しなければ、必ず拒否する」Cedar(AWS の認可) 「コンパイルしても、プログラムの意味が変わらない」CompCert(C コンパイラ) 「どのプロセスも、他のプロセスのメモリを読めない」seL4(OS カーネル) どれも全ての入力に対する主張。テストでは閉じられず、証明なら機械が確認できる 31/41

Slide 32

Slide 32 text

副作⽤の分離が 対応を実⽤にする ラムダ計算 (1930s) 関数型プログラミング 純粋関数、参照透過性 型付きラムダ計算 型システム 型検査、型推論、ADT Curry-Howard 対応 型 = 命題 プログラム = 証明 依存型 型が値に依存する 形式検証 Lean 、Agda 、Rocq 32/41

Slide 33

Slide 33 text

step 3 このつながりを、 実務の設計にどう活かすか 副作用の分離は、証明への入口だった。その入口を、日々の設計の道具にする 33/41

Slide 34

Slide 34 text

書く速度は上がる、確かめる速度は上がらない AI で書く速度が上がるほど、正しさの確認が人間に積み上がる LLM 生成コードのコンパイルエラーは、94% が型検査の失敗だった(2025 年の研究) 機械による検査が、AI の間違いを最前線で捕まえている Cassidy Williams "Why AI is pushing developers toward typed languages" (GitHub Blog 2026) https://github.blog/ai-and-ml/llms/why-ai-is-pushing-developers-toward-typed-languages/ 34/41

Slide 35

Slide 35 text

関数型のスタイルは、 AI との協働に向く シグネチャが、人間と AI の共通言語になる 純粋な関数は外の文脈に依存しないから、AI に渡すべき情報が 型に収まる 型が生成の道筋を絞り、網羅チェックが考え漏れを数える 参照透過なら、AI の書き換えを型検査と等式推論で 機械的に確かめられる そして、副作用を分離する書き換え自体を AI が手伝ってくれる 35/41

Slide 36

Slide 36 text

GitHub で最も使われる⾔語 上位 3 ⾔語の順位、2023 → 2025 1位 2位 3位 TypeScript Python JavaScript 2023 2024 2025 2025/8 伸びているのは TypeScript だけではない 型付き⾔語のコントリビュータ増加率(前年⽐) Luau Typst TypeScript +194% +108% +66% 型付き言語が、 選ばれ始めている TypeScript は GitHub で最も使われる言語になった 伸びているのは TypeScript だけではなく、 型付き言語というカテゴリ全体 AI 支援開発が型付き言語を後押ししたと GitHub は分析している Cassidy Williams "Why AI is pushing developers toward typed languages" (GitHub Blog 2026) https://github.blog/ai-and-ml/llms/why-ai-is-pushing-developers-toward-typed-languages/ 36/41

Slide 37

Slide 37 text

ドメインロジックを表現するための型 コアの中は Result。失敗を値にして、例外で制御を飛ばさない 状態は直和型。業務が許さない状態を、そもそも表現できなくする 値はスマートコンストラクタ。検証を通った値にだけ封をして、型を証拠にする 境界は parse, don't validate。外から来る値は、検査して型に変換してから持ち込む Scott Wlaschin "Railway Oriented Programming" https://fsharpforfunandprofit.com/rop/ Alexis King "Parse, don't validate" (2019) https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ 37/41

Slide 38

Slide 38 text

型とテストの役割分担 型が守るもの 「ありえない状態」を存在させない コンパイル時に、全ケースを機械が検査 テストが守るもの 「ありうる振る舞い」の正しさ 実行時に、代表的な実例で検証 型で排除した分だけ、書くべきテストが減る 破られると事故になる命題を型に載せ、残りはテストで守る。この選別が設計になる Edsger W. Dijkstra "Notes on Structured Programming" (1970) https://www.cs.utexas.edu/~EWD/ewd02xx/EWD249.PDF 38/41

Slide 39

Slide 39 text

型検査と証明の役割 型検査が守るもの 「ありえない状態」を機械が検査 コンパイル時に自動で。ただし any で破れる 証明が守るもの 仕様そのものを厳密に保証 全域性と依存型が要る(Lean など) 実務の型検査は、証明の弱い版 39/41

Slide 40

Slide 40 text

なぜ関数型プログラミングで 「型」と「証明」が語られるのか 関数型と型システムは、どちらも ラムダ計算から生まれ、一緒に発展してきた 副作用を消すと、型が関数の影響範囲を全て 語る。そのとき型は命題、プログラムは 証明として読める(Curry-Howard 対応) Result も直和型もスマートコンストラクタも、 「この状態はありえない」を機械に検査させる道具 AI がコードを書く時代は、破られると事故になる 命題を選んで型に載せる。この選別が設計になる 40/41

Slide 41

Slide 41 text

https://techtrain.dev/mentors