Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
関数型プログラミングのメリットって何だろう?
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
わんこ(Wanko_IT)
July 07, 2026
Programming
260
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
関数型プログラミングのメリットって何だろう?
わんこ(Wanko_IT)
July 07, 2026
More Decks by わんこ(Wanko_IT)
See All by わんこ(Wanko_IT)
モナドと出会う
wanko_it
0
8
バックエンドにElysiaJSを採用して気付いた、良い点・悪い点
wanko_it
1
440
安易なコード批判はやめよう
wanko_it
0
90
『リコリス・リコイル』に学ぶ!! 〜キャリア戦略における計画的偶発性理論と変わる勇気の重要性〜
wanko_it
2
1.2k
V8のJITコンパイルを完全に理解するLT
wanko_it
0
57
Other Decks in Programming
See All in Programming
Webの地図
yosuke_furukawa
PRO
6
4.6k
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
200
WebMCP Challenge に星空観察アプリで参加した話
okajun35
0
180
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
1
290
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
180
The Good Stuff, Not the Slop: Engineering High-Quality Android Apps with Modern AI Tooling
danybony
1
260
wkhtmltopdfの次どうするか問題2026
willnet
2
1.5k
Heart of Swift Concurrency
koher
0
920
[GoCon2026] When Goroutines Are Not Enough: Runtime Locality in High-Throughput Go
takehaya
6
2.3k
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
220
【高い買い物LT会】初任給で話題の国産フィジカルAIを買った話
akagami
PRO
0
160
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
310
Featured
See All Featured
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
The browser strikes back
jonoalderson
0
1.7k
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
5
700
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
500
Raft: Consensus for Rubyists
vanstee
142
7.7k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.3k
Documentation Writing (for coders)
carmenintech
77
5.5k
Optimizing for Happiness
mojombo
378
71k
30 Presentation Tips
portentint
PRO
1
400
Become a Pro
speakerdeck
PRO
31
6.3k
Speed Design
sergeychernyshev
33
2.1k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
Transcript
関数型プログラミングの メリットってなんだろう? 清水日向 社内発表 / 10分
背景 私たちのチームでは関数型言語 Clojure を使って開発しています。日々の開発の中で「関数型プ ログラミングって、結局何が嬉しいんだろう?」と疑問に思い、調べた内容を共有します。 「なんとなく良さそう」で終わらせず、関数型プログラミングがどんなバグや問題を防いでくれ るのかを、実際のコードで確認していきます。難しい理論の話はしないので、気楽に聞いてくだ さい。 ※ コード例は
Clojure ではなく Java / Scala で書いています。括弧だらけの Clojure より読み慣れた構文のほうが、違いが伝 わりやすいので。
アジェンダ 01 関数型プログラミングとは何か 定義を確認し、本質が「不変性」にあることを押さえる 02 値の不変性とは何か 変数で表現する言語と、定数だけで表現する言語のコードを比べる 03 値が不変だと何が嬉しいのか 可変であることの問題2つ
— 共有ミュータブル状態・時間的結合 — をコードで見る 04 まとめ — なぜ合理的な選択なのか 「未知の未知」というソフトウェアの複雑性と不変性の関係
01 ─ 関数型プログラミングとは何か 関数型プログラミングの定義 そもそも、関数型プログラミングとは何でしょうか? 調べると、以下のような特徴が挙げられています。 参照透過性 同じ入力には常に同じ出力を 返す 値の不変性
一度作られた値は決して変更 されない 第一級関数 関数を値として扱い、引数や 戻り値にできる 高階関数の利用 関数を受け取る・返す関数を 活用するスタイル …ただし、広く認められた共通の定義は確立されていない。そこで今回は、ある定義を採用します。
01 ─ 関数型プログラミングとは何か 関数型プログラミングとは、変数のないプログラミングと言え るだろう。関数型プログラムの値は変化しないのである。 『関数型デザイン』Robert C. Martin 今回はこの定義を採用します。つまり、関数型プログラミングの本質は「不変性」に ある。
02 ─ 値の不変性とは何か 値の不変性 Java・C・PHP・Ruby などのオブジェクト指向・手続き型の言語は変数(変更可能な値)で状態を表現する。一方で Clojure・Scala・Erlang などの関数型志向の言語は、定数(不変な値)を基本とする。 非関数型(Java)— 変数を書き換える
class Wallet { private int money; public Wallet(int money) { this.money = money; } public int getMoney() { return money; } public void addMoney(int amount) { money = money + amount; // 中身を書き換える } } Wallet wallet = new Wallet(1000); wallet.getMoney(); // 1000 wallet.addMoney(500); wallet.getMoney(); // 1500 ← 状態が変わった 関数型(Scala)— 新しい値を作る case class Wallet(money: Int) def addMoney(wallet: Wallet, amount: Int): Wallet = Wallet(wallet.money + amount) // 新しい財布を作る val wallet1 = Wallet(1000) val wallet2 = addMoney(wallet1, 500) wallet1.money // 1000 ← 変わっていない! wallet2.money // 1500 ← 新しくできた財布 関数型では、値は定数が基本。状態の変化は「既存の値をもとに作られた新しい定数」として表現する。
値が不変だと、何が嬉しい? 逆から考える — 値が可変であることに伴う問題は2つある 問題 ① ── いまから見る 共有ミュータブル状態 同じインスタンスへの変更が、予期せぬ場所へ波及する
問題 ② 時間的結合 変更の途中に「不正な中間状態」が存在してしまう
03 ─ 値が不変だと何が嬉しいのか 問題① 共有ミュータブル状態(Java) Q. このコード、何が出力されるでしょう? 月末ごとの残高を記録するクラス class BalanceHistory
{ // 特定地点での財布の状態を保持 private List<Wallet> snapshots = new ArrayList<>(); // 「今この瞬間の状態」を記録 public void recordSnapshot(Wallet wallet) { snapshots.add(wallet); } // 記録された履歴を取得 public List<Wallet> getSnapshots() { return snapshots; } } 利用側のコード Wallet wallet = new Wallet(1000); BalanceHistory history = new BalanceHistory(); history.recordSnapshot(wallet); // 1月末: 1000円を記録 wallet.addMoney(500); history.recordSnapshot(wallet); // 2月末: 1500円を記録 wallet.addMoney(-1500); history.recordSnapshot(wallet); // 3月末: 0円を記録 for (Wallet snap : history.getSnapshots()) { System.out.println(snap.getMoney()); }
03 ─ 値が不変だと何が嬉しいのか 予想と異なる出力 直感的な予想 1000 1500 0 各月末に記録した瞬間の残高が、そのまま残っているは ず…
実際の出力 0 0 0 1月末の「1000円」も2月末の「1500円」も消えてしまっ た
03 ─ 値が不変だと何が嬉しいのか 原因: 3要素は同一インスタンス recordSnapshot(Wallet wallet) の引数は参照渡し。リストに追加されるのはコピーではなく、同じWalletへの 参照。3要素が指す実体は1つで、その値は最後の変更(3月末=0円)の状態になっている。 ①
リストの中身を図にすると snapshots[0] ──▶ snapshots[1] ──▶ snapshots[2] ──▶ Wallet(money = 0) たった1つの同じインスタンス ② コードで要素の等価性を確認しても、同一 snapshots.get(0) == snapshots.get(1) // true snapshots.get(0) == snapshots.get(2) // true snapshots.get(1) == snapshots.get(2) // true 共有ミュータブル状態では、処理の影響が予期せぬ形で波及する。アプリ全体を正常に保つために「考えるべき こと」が増大してしまう。
03 ─ 値が不変だと何が嬉しいのか 不変な値による解決(Scala) case class BalanceHistory(snapshots: List[Wallet] = Nil)
{ def recordSnapshot(wallet: Wallet): BalanceHistory = BalanceHistory(snapshots :+ wallet) } // 1月末: 1000円 val wallet1 = Wallet(1000) val history1 = BalanceHistory().recordSnapshot(wallet1) // 2月末: 1500円 val wallet2 = wallet1.addMoney(500) val history2 = history1.recordSnapshot(wallet2) // 3月末: 0円 val wallet3 = wallet2.addMoney(-1500) val history3 = history2.recordSnapshot(wallet3) history3.snapshots.foreach(w => println(w.money)) // 1000, 1500, 0 ← 期待どおり! ポイント 1 プログラム中のすべての値は変更不能かつ 異なる実体であると、言語が保証する ポイント 2 異なる状態のWalletは別々の実体として保 存され、後から変更される心配がない ポイント 3 「スナップショット」が言葉どおりの意味 で機能し、記録した瞬間の状態がそのまま 残る 出力: 1000 → 1500 → 0 ✓
値が可変であることの問題、もう1つ 今度は「空間」ではなく「時間」に潜む問題 問題 ② ── いまから見る 時間的結合 変更の途中に「不正な中間状態」が存在してしまう 問題 ①
── 解決 ✓ 共有ミュータブル状態 不変な値なら、記録した状態が後から変わることはない
03 ─ 値が不変だと何が嬉しいのか 問題② 時間的結合(Java) class Wallet { private int
balance = 1000000; // 残高(100万円) private int count = 0; // 送金回数 // 送金を行うメソッド public void transfer(int amount) { balance -= amount; // ← この瞬間「残高だけ減って回数は0のまま」 // という業務上ありえない財布が存在する count += 1; } } balance と count はセットで変わるべき値だが、 変数は1つずつしか書き換えられないため、途中に 不正な中間状態が実在する瞬間が生まれる。 その結果「この瞬間に参照・操作してはいけない」 という時間軸上の制約が生まれる。コードのどこ にも書かれていないこの依存が時間的結合。 この一瞬を別スレッドが読み取れば再現困難なバグに。 あいだで例外が起きれば不整合なまま残り続ける。 transfer() 実行中の時間軸 balance -= amount; ▶ 不正な中間状態 残高: 99万円 / 送金回数: 0回 ▶ count += 1;
03 ─ 値が不変だと何が嬉しいのか 同時に確定する状態(Scala) case class Wallet(balance: Int, count: Int)
{ def transfer(amount: Int): Wallet = Wallet(balance - amount, count + 1) // ↑ 残高と回数が同時に確定した新しい財布 } val w0 = Wallet(1000000, 0) val w1 = w0.transfer(10000) // w0: (1000000, 0) … 送金前の財布 // w1: ( 990000, 1) … 送金後の財布 // 「残高だけ減った財布」は書きようがない 不変な値では、状態の変化を全フィールドが同時 に確定した新しい値としてしか表現できない。 つまり不正な中間状態が、そもそも実在しない。 存在するのは送金前と送金後、2つの正しい財布 だけ。 中間状態が消えれば「この瞬間に参照・操作して はいけない」という制約も丸ごと消える — 守るべ きルールではなく、ルールが必要な状況自体をな くす。 可変(Java) 1つの財布が時間とともに姿を変え、途中の不正な姿 が存在してしまう。 不変(Scala) 存在するのは w0 と w1 という2つの完成品だけ。途 中がない。
04 ─ まとめ: なぜこれが重要か “Of the three manifestations of complexity,
unknown unknowns are the worst.” John Ousterhout『A Philosophy of Software Design, 2nd Edition』 ソフトウェアの複雑性のうち最悪なのが「未知の未知」— 問題が潜んでいるかどうかさえ、知る術がないこ と。バグが出たとき、初めてその存在に気づく。 ここまで見てきた可変な値に起因するバグは、特定の手順・条件でしか起きない。そのため動作検証やテス トをすり抜け、バグが顕在化するまで問題の存在に気づけない — 未知の未知そのものである。 不変な値なら、不整合な状態はそもそも作れない。「未知の未知」になる前に、言語が芽を摘んでくれる。
04 ─ まとめ まとめ 関数型プログラミングとは、不正な状態を発生させにくくするプログラミングスタイルで ある。 1 本質は不変性 — あらゆる値を定数として扱う
状態の変化は「既存の値をもとにした新しい定数」として表現する 2 共有ミュータブル状態と時間的結合を構造的に排除できる 予期せぬ波及も、不正な中間状態も、そもそも表現できない 3 銀の弾丸ではないが、合理的な選択肢 再現困難でテストをすり抜ける「未知の未知」型バグの発生確率を下げられる ご清聴ありがとうございました