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
Java で学ぶ 代数的データ型
Search
301 Moved Permanently
June 06, 2025
Technology
4
1.8k
Java で学ぶ 代数的データ型
JJUG CCC 2025 Springの登壇資料です。
301 Moved Permanently
June 06, 2025
Tweet
Share
More Decks by 301 Moved Permanently
See All by 301 Moved Permanently
TypeScript 上達の道
ysknsid25
24
6k
Kotlinで学ぶ 代数的データ型
ysknsid25
5
1.5k
Type Challengesに新しい問題を追加して Type ChallengesのMaintainerになった話
ysknsid25
3
1k
統計データで2024年の クラウド・インフラ動向を眺める
ysknsid25
2
1.3k
GAS × Discord bot × Gemini で作ったさいきょーの情報収集ツール
ysknsid25
1
2.1k
テストコード品質を高めるためにMutation Testingライブラリ・Strykerを実戦導入してみた話
ysknsid25
8
4k
そうだ、神戸へ行こう
ysknsid25
2
17k
テストコードの品質を客観的な数値で担保しよう〜Mutation Testのすすめ〜
ysknsid25
12
5.9k
「ばん・さく・つき・たー!」にならないためにSHIROBAKOから 学んだこと
ysknsid25
4
1.6k
Other Decks in Technology
See All in Technology
Oracle Database@Azure:サービス概要のご紹介
oracle4engineer
PRO
2
200
AgentCoreとStrandsで社内d払いナレッジボットを作った話
motojimayu
1
990
さくらのクラウド開発ふりかえり2025
kazeburo
2
1.2k
AI との良い付き合い方を僕らは誰も知らない
asei
0
270
Building Serverless AI Memory with Mastra × AWS
vvatanabe
0
610
M&Aで拡大し続けるGENDAのデータ活用を促すためのDatabricks権限管理 / AEON TECH HUB #22
genda
0
270
AI駆動開発ライフサイクル(AI-DLC)の始め方
ryansbcho79
0
200
意外と知らない状態遷移テストの世界
nihonbuson
PRO
1
270
Strands Agents × インタリーブ思考 で変わるAIエージェント設計 / Strands Agents x Interleaved Thinking AI Agents
takanorig
5
2.1k
20251218_AIを活用した開発生産性向上の全社的な取り組みの進め方について / How to proceed with company-wide initiatives to improve development productivity using AI
yayoi_dd
0
720
MySQLとPostgreSQLのコレーション / Collation of MySQL and PostgreSQL
tmtms
1
1.3k
Knowledge Work の AI Backend
kworkdev
PRO
0
280
Featured
See All Featured
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
0
67
Stop Working from a Prison Cell
hatefulcrawdad
273
21k
4 Signs Your Business is Dying
shpigford
186
22k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
410
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.2k
Leo the Paperboy
mayatellez
0
1.3k
Become a Pro
speakerdeck
PRO
31
5.7k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
180
Java REST API Framework Comparison - PWX 2021
mraible
34
9k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
82
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
0
130
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
280
Transcript
Kanon #jjug_ccc Java で学ぶ 代数的データ型 ysknsid25 ysknsid25.bsky.social
⛳ このセッションのゴール ⛳ 2 • 代数的データ型とは何かを理解できる • 代数的データ型をJavaで表現することができるようになる
関数型プログラミングといえば? な キーワードを 1つ想像してください 3
4 あなたが想像したのはこれですね? 純粋関数
5 純粋関数とは • 戻り値は常に一つ • 関数は引数にのみ基づいて戻り値を計算する • 関数は既存の値を変更しない
6 ではこういう純粋関数はどうだろう? public static String activityStatus(Date latestLoginDate, Date referenceDate) {
if (latestLoginDate == null) { return "INACTIVE"; } Calendar calendar = Calendar.getInstance(); calendar.setTime(referenceDate); calendar.add(Calendar.YEAR, -1); Date oneYearAgo = calendar.getTime(); return latestLoginDate.after(oneYearAgo) ? "ACTIVE" : "INACTIVE"; } 戻り値は1つの文字列で 引数にのみ基づいてるし 既存の値は変えてない 例なので結構極端 最終ログインが 1年前ならINACTIVE、1年以内ならActiveとする
7 先の関数を呼び出す public static void main (String[] args) { //
do something… String status = activityStatus(latestLoginDate, referenceDate) // do something… } INACTIVE ACTIVE 実装を見ないと 振る舞いがわからない 引数はこの組み合わせ意味 (活動中かどうかの条件 )を 持っているが それは実装を見ないとわから ない
8 純粋関数はなんのため? 関数の宣言を見て振る舞いが想像できる & 期待どおりに振る舞う 代数的データ型が役立つ!!
代数的データ型 9
代数的データ型 = 直積型 & 直和型 10 また知らないワード…
11 直積型 代数的データ型 • ここでは 星座 × 年齢。A × B
× C … 掛け算なので直積 • JavaでいうとRecordやBean Class • 要はデータクラス 年齢 星座 (蟹, 20) (双子, 30) (射手, 40) (山羊, 20) public record PersonInfo( String constellation, int age ){}
12 直和型 代数的データ型 • ここでは 星座 は必ず12個で、牡牛座であり牡牛座であることはありえない。 • 和集合 A
∪ B ただし A ∩ B = φ … 直和 • Javaでいうとenumやsealed class 星座 public enum Constellation { ARIES, // おひつじ座 TAURUS, // おうし座 GEMINI, // ふたご座 CANCER, // かに座 LEO, // しし座 VIRGO, // おとめ座 LIBRA, // てんびん座 SCORPIO, // さそり座 SAGITTARIUS, // いて座 CAPRICORN, // やぎ座 AQUARIUS, // みずがめ座 PISCES // うお座 } 牡羊 牡牛 双子 蟹 乙女 天秤 蠍 射手 山羊 水瓶 魚 獅子
代数的データ型 = 直積型 & 直和型 13 改めて
代数的データ型が ないとき 14
15 代数的データ型になっていないコード 代数的データ型 import java.util.Optional; public record PeriodInYears(int start, Optional<Integer>
end){}; public static void main(String[] args) { PeriodInYears p1 = new PeriodInYears(1981, Optional.empty()); PeriodInYears p2 = new PeriodInYears(1968, Optional.of(1980)); System.out.println(p1); // PeriodInYears[start=1981, end=Optional.empty] System.out.println(p2); // PeriodInYears[start=1968, end=Optional[1980]] } 活動期間を表現したい endが存在しない = 活動中 endが存在する = 活動終了 と表現できないだろうか? 活動中なのに活動終了と判定され る間違いも起きそう 直積の概念のみが反映された状態のコード
16 代数的データ型が あるとき
17 代数的データ型になったコード 代数的データ型 // 直和型 public sealed interface YearsActive permits
StillActive, ActiveBetween {} // record(直積)×sealed(直和)の代数的データ型 public record StillActive(int since) implements YearsActive { /** 妥当性の検証は省略 */ } public record ActiveBetween(int start, int end) implements YearsActive { /** 妥当性の検証は省略 */ } public static void main(String[] args) { YearsActive y1 = new StillActive(2005); YearsActive y2 = new ActiveBetween(1990, 2000); System.out.println(y1); // StillActive[since=2005] System.out.println(y2); // ActiveBetween[start=1990, end=2000] } データの意味が一目でわかるようになったし、間違いも起こりにくそう
18 sealedではなくenumじゃだめなの? 代数的データ型 public enum YearsActive { STILL_ACTIVE { private
int since; @Override void setData(int a, int b) { this.since = a; } }, ACTIVE_BETWEEN { private int start; private int end; @Override void setData(int a, int b) { this.start = a; this.end = b; } }; abstract void setData(int a, int b); } enumで直積の性質を表現するのは無理がある。 以下のようにだいぶ無理があるコードができあがる。int b を無理やり入れないとだし、どう考えてもスマートじゃない public static void main(String[] args) { YearsActive y1 = YearsActive.STILL_ACTIVE; y1.setData(2005, 9999); // 9999ってなんだ・・・ YearsActive y2 = YearsActive.ACTIVE_BETWEEN; y2.setData(1990,2000); System.out.println(y1); // STILL_ACTIVE System.out.println(y2); // ACTIVE_BETWEEN }
19 継承じゃだめなの? 代数的データ型 sealedではなく継承を使ってしまうと、理論上無限の集合が出来上がる = 直和の性質がない YearsActive StillActive ActiveBetween PreviousLife
知らないところで勝手に前世を定義できてしまう もちろん来世も定義できる
20 さらなる恩恵を受ける 代数的データ型 // 直和型 public sealed interface YearsActive permits
StillActive, ActiveBetween {} // record(直積)×sealed(直和)の代数的データ型 public record StillActive(int since) implements YearsActive { /** 妥当性の検証は省略 */ } public record ActiveBetween(int start, int end) implements YearsActive { /** 妥当性の検証は省略 */ } public static void main(String[] args) { YearsActive y1 = new StillActive(2005); YearsActive y2 = new ActiveBetween(1990, 2000); System.out.println(y1); // StillActiveならsinceだけ出力 System.out.println(y2); // ActiveBetweenは開始と終了を出力 } System.out.println()の内容をデータによって切り分ける関数を作るとする
21 代数的データ型の威力 代数的データ型 public sealed interface YearsActive permits StillActive, ActiveBetween
{} public record StillActive(int since) implements YearsActive {} public record ActiveBetween(int start, int end) implements YearsActive {} public static void main(String[] args) { YearsActive y1 = new StillActive(2005); YearsActive y2 = new ActiveBetween(1990, 2000); System.out.println(getYearsMessage(y1)); System.out.println(getYearsMessage(y2)); } static String getYearsMessage(YearsActive ya) { return switch (ya) { case StillActive sa -> "Still active since " + sa.since(); case ActiveBetween ab -> "Active between " + ab.start() + " and " + ab.end(); }; } • シグネチャから処理が明らかになった • 引数として必要なデータが何か?も明らか • データの不整合が起こり得ない ◦ 先のenumでみた9999とか • YearsActiveでとりうる値の範囲が限定され ることで、switchにデフォルトが生えない ◦ コンパイル時点でデータの整合性が担 保される • 逆にYearsActiveに新たな値が増えた場合 は、getYearsMessage でエラーが出るので修 正漏れが出ない
22 まとめ • 代数的データ型 = 直積型 & 直和型 ◦ enumは直積の性質がない
◦ 継承は直和の性質がない • 代数的データ型を使うことでより明示的なシグネチャを定義できる • 代数的データ型を使うことで取りうるデータの範囲を型で表現できる • 代数的データ型はコンパイル時点での品質保証に寄与する
Happy Hacking !! 水瀬いのり さんが推し の @ysknsid25 @ysknsid25.bsky.social Presented by
Kanon でした
24 • これまでの`YearsActive`データモデルを実際に定義しましょう • `master`ブランチにリファクタ前のコードがあります • `answer`ブランチはリファクタ後のコードです。さっきまで出していたサン プルと同じ内容になっています • 今学んだ代数的データ型を定義し、`master`ブランチのテストコードが通
るように修正してみてください 実際に代数的データ型を書いてみよう! 時間が余れば https://github.com/ysknsid25/jjug-spring-2025