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
Welcome to the "Fantasy Land" 🧚 − 代数的構造をめぐる冒険 −
Search
TAKASE Kazuyuki
November 23, 2025
Programming
200
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Welcome to the "Fantasy Land" 🧚 − 代数的構造をめぐる冒険 −
このスライドは、2025/11/23「TSKaigi Hokuriku 2025」で発表したものです。
cf.
https://hokuriku.tskaigi.org/talks/31
TAKASE Kazuyuki
November 23, 2025
More Decks by TAKASE Kazuyuki
See All by TAKASE Kazuyuki
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
1
240
技育プロジェクト公式メンターがピックアップ!− おすすめ書籍 & 開発ツール一挙紹介 − / Geek Project Mentors' Picks: Books & Dev Tools
guvalif
0
96
型付け力を強化するための Hoogle のすゝめ / Boosting Your Type Mastery with Hoogle
guvalif
1
1.2k
A Tour of Anti-patterns for Functional Programming
guvalif
0
4.2k
"数学" をプログラミングしてもらう際に気をつけていること / Key Considerations When Programming "Mathematics"
guvalif
0
830
"情報設計" と "体験設計" の観点から捉える UI 構築の考え方 / Approaches to UI Construction from the Perspectives of "Information Architecture" and "Experience Design"
guvalif
0
930
Chatwork における採用広報と技術広報のリアル / Trial & Error of New Grad Developer Relations at Chatwork
guvalif
0
670
本当に 0 からの 関数型プログラミングの歩き始め方 / How to Walk into Functional Programming from Scratch
guvalif
1
1.4k
宣言的 UI 時代のクライアントサイド DDD 大考察 / Client-side DDD in the Age of Declarative UI
guvalif
11
11k
Other Decks in Programming
See All in Programming
コンパウンドプロダクト開発のためのローカルプロセスマネージャー再発明 #layerxgo
izumin5210
0
640
PHPプロジェクトの結合バランスを可視化する #php_night
kajitack
0
220
まずはプロンプトガイドを読もう、話はそれからだ
kiakiraki
1
260
Press start. Python's next generation.
willingc
PRO
3
310
AIを上手に使っていこうとしたら越境せざるを得なくなった話 〜実践1年で見えた境界を越えなければならない理由と進め方〜 / Crossing borders with AI
tomoyakitaura
3
1.1k
Laravelのアプリケーションをどこにデプロイするか #ツナギメオフライン.9
akase244
0
120
Seeing Through Serverless: Observability for AWS Lambda with ADOT and CloudWatch Application Signals
seike460
PRO
1
120
数年滞っていたダークモード対応をおよそ2週間で完了させる
chigichan24
0
680
高専、大学編入、そして未踏へ〜プロダクト開発とキャリアの歩み - Technical College, University Transfer, and On to “Mitou” / My Journey in Product Development and Career
pkmiya
0
140
初めての模倣学習とVLA
natsutan
0
490
MIZARU@SPAJAM2026 第二回予選
1901drama
0
110
AWS DevOps Agentで インシデント対応をAIに任せたい
honmarkhunt
6
2.4k
Featured
See All Featured
Unsuck your backbone
ammeep
672
58k
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
920
Deep Space Network (abreviated)
tonyrice
0
290
It's Worth the Effort
3n
188
29k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
480
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
370
How to build a perfect <img>
jonoalderson
1
6k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
560
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Side Projects
sachag
455
43k
Transcript
Welcome to the "Fantasy Land" 🧚 − 代数的構造をめぐる冒険 − #TSKaigi
Hokuriku 2025 --- @Guvalif (TAKASE Kazuyuki)
余談) 運営スタッフの @berlysia さんとは、同じ会社 & 本部の所属です 自己紹介 - 高瀬
和之 (TAKASE Kazuyuki) >=> 𝕏:@Guvalif Profile { works = [ "IoT エンジニア", "フロントエンド・エンジニア", "開発人事", "TechPM (← 現職)", "エンジニア育成 (← 複業)" ], memo = "関数型 XXX を名乗りがち 😗" }
冒険の地図 (本編) 🧭 >=> `Promise` の型定義 `Result` の型定義 `Promise` の振る舞い
`Result` の振る舞い 代数的構造の仕様 抽象化した型定義 抽象化した振る舞い 代数的構造 "Fantasy Land" 🧚
冒険の地図 (エピローグ) 🧭 >=> まとめ 関連する Proposals 関数による実装 代数的構造の仕様 "Fantasy
Land" 🧚
I. `Promise` と `Result` の型定義
`Promise` の型定義 es5.d.ts を参照することで `PromiseLike<T>` という型定義が得られる (冗長さを省くと以下): ``` ``` >=>
interface PromiseLike<T> { then<A, B>( onfulfilled: (value: T ) => A | PromiseLike<A>, onrejected: (reason: any) => B | PromiseLike<B>, ): PromiseLike<A | B>; } - `then` メソッドを持つ - `onfulfilled` および `onrejected` として、Callback を設定できる - いずれの Callback も ある型の値 もしくは `PromiseLike` で包まれたある型の値 を返す
`Result` の型定義 (1) result.ts を参照することで `Result<T, E>` という型定義が得られる (冗長さを省くと以下): ```
``` >=> type Result<T, E> = Ok<T, E> | Err<T, E>; class Ok<T, E> { map<A> (f: (t: T) => A ): Result<A, E> { ... } andThen<A, F>(f: (t: T) => Result<A, F>): Result<A, E | F> { ... } } class Err<T, E> { map<B> (f: (t: T) => B ): Result<B, E> { ... } andThen<B, F>(f: (t: T) => Result<B, F>): Result<B, E | F> { ... } }
`Result` の型定義 (2) 型定義が対称なので、簡単のために `Ok<T, E>` のみに着目すると ... ``` ```
>=> type Result<T, E> = Ok<T, E> | Err<T, E>; class Ok<T, E> { map<A> (f: (t: T) => A ): Result<A, E> { ... } andThen<A, F>(f: (t: T) => Result<A, F>): Result<A, E | F> { ... } } - `map` および `andThen` メソッドを持つ - それぞれ `f` として Callback を設定できる: - `map` の Callback は ある型の値 を返す - `andThen` の Callback は `Result<?, F>` で包まれたある型の値 を返す
Q. なんだか似ていると思った方
e.g. `onfulfilled` に着目してみる (1) `onfulfilled` に関係ない部分を削除し Pretify すると ... ```
``` >=> interface PromiseLike<T> { then<A, B>( onfulfilled: (value: T ) => A | PromiseLike<A>, onrejected : (reason: any) => B | PromiseLike<B>, ): PromiseLike<A | B>; } interface PromiseLike<T> { then<A>(onfulfilled: (value: T) => A | PromiseLike<A>): PromiseLike<A>; }
ここで、シンボル名を無視して 型に着目 すると、定義の類似 が見て取れる ``` ``` e.g. `onfulfilled` に着目してみる (2)
`then` の定義を Overload すると ... (※ 厳密には完全分離できない可能性があることに注意) ``` ``` >=> interface PromiseLike<T> { then<A>(onfulfilled: (value: T) => A ): PromiseLike<A>; then<A>(onfulfilled: (value: T) => PromiseLike<A>): PromiseLike<A>; } class Ok<T, E> { map<A> (f: (t: T) => A ): Result<A, E> { ... } andThen<A, F>(f: (t: T) => Result<A, F>): Result<A, E | F> { ... } }
現在地点の確認 >=> `Promise` の型定義 `Result` の型定義 `Promise` の振る舞い `Result` の振る舞い
代数的構造の仕様 抽象化した型定義 抽象化した振る舞い 代数的構造 "Fantasy Land" 🧚 ✅ ✅ ✅
II. `Promise` と `Result` の振る舞い
暗黙的な `this` にも型を明示することで、`then` メソッドの振る舞いを整理してみる: with Promise _then(onfulfilled)_ `Promise` の振る舞い >=>
Promise<T> _onfulfilled_ Promise<A> this T A _then(onfulfilled)_ Promise<T> Promise<A> this T _onfulfilled_ ※ 簡単のために `onfulfilled` のみに着目 then<A>(this: PromiseLike<T>, onfulfilled: (value: T) => A ): PromiseLike<A> then<A>(this: PromiseLike<T>, onfulfilled: (value: T) => PromiseLike<A>): PromiseLike<A>
暗黙的な `this` にも型を明示することで、`map` および `andThen` メソッドの振る舞いを整理してみる: with Result _map(f)_ `Result`
の振る舞い >=> Result<T, E> _f_ Result<A, E> this T A _andThen(f)_ Result<T, E> Result<A, E> this T _f_ ※ 簡単のために型パラメータ `E = F` として図示 map<A> (this: Result<T, E>, f: (t: T) => A ): Result<A, E> andThen<A>(this: Result<T, E>, f: (t: T) => Result<A, E>): Result<A, E>
`PromiseLike<?>` と `Result<?, E>` を、ざっくり `M<?>` として抽象化してみる: _foo(f)_ 似ている Interface
に着目する >=> M<T> _f_ M<A> this T A _bar(kf)_ M<T> M<A> this T _kf_ ※ いったんそれぞれのメソッド名は仮置き with M foo<A>(this: M<T>, f: (t: T) => A ): M<A>; bar<A>(this: M<T>, kf: (t: T) => M<A>): M<A>;
Q. 本当に抽象化しても大丈夫 ...? 型 と Interface が似ていることは確かめたが、振る舞いが対応づくか は明らかになっていない!
現在地点の確認 >=> `Promise` の型定義 `Result` の型定義 `Promise` の振る舞い `Result` の振る舞い
代数的構造の仕様 抽象化した型定義 抽象化した振る舞い 代数的構造 "Fantasy Land" 🧚 🤔 ✅ ✅
III. 代数的構造と "Fantasy Land" 🧚
- 型 の表現は似ている ✅ - Interface の表現は似ている ✅ - しかし、振る舞いの対応
までは確信が持てない 🤔 現状の整理 >=> _foo(f)_ M<T> _f_ M<A> this T A _bar(kf)_ M<T> M<A> this T _kf_ with M
"代数的構造" を考える 【 "代数的構造" とは?】 - おもに抽象代数学で議論される概念 - 型 (≒
集合) と Interface (≒ 演算) に関して、どのようなルールが満たされるか を定めるもの - プログラミングで言うところの、デザインパターンに相当するもの 【 なぜ "代数的構造" を考えたいか?】 - 数学に由来する概念なので、論証の正確性 を担保しやすい - 19 世紀から研究されているので、巨人の肩に乗りやすい 🥳 >=>
JavaScript における代数的構造の標準化仕様, "Fantasy Land" 🧚 プログラミングにおいて頻出の代数的構造を体系化 し、満たすべきルールを仕様としてまとめたもの: >=>
事前知識:TypeScript ⇔ Fantasy Land における型シグネチャの比較 >=> 関数型 多相型 (いわゆるジェネリクス) カインド
(型関数) 型制約 // `,` 区切りで引数を増やす (_0: A, _1: B) => C -- `->` で連結して引数を増やす A -> B -> C // 項に紐づく `<T>` 部分で多相性を明示 length: <T>(_0: T[]) => number -- 小文字で記述することで多相性を明示 length :: [t] -> Int // 型に紐づく `<T>` 部分で型引数を明示 type Thenable<T> = ... -- スペース区切りで型引数を明示 Thenable t // `extends` に続けて制約を記述 sort: <T extends Ord>(_0: T[]): => T[] -- `=>` の手前に制約を記述 sort :: Ord t => [t] -> [t]
次のような型 (と Interface) を考える: ``` ``` e.g. Setoid の仕様を読み解いてみる >=>
interface S { ['fantasy-land/equals'](s: S): boolean; } `S` が Setoid という代数的構造を満たすとしたら 、任意のインスタンス `a`, `b`, `c` に対して: 1. `a['fantasy-land/equals'](a) === true` 2. `a['fantasy-land/equals'](b) === b['fantasy-land/equals'](a)` 3. If `a['fantasy-land/equals'](b)` and `b['fantasy-land/equals'](c)` , then `a['fantasy-land/equals'](c)` ... これら 3 つのルールが成立 する
試しに以下の Interface に関して、Fantasy Land の仕様を探してみる 🔍: というわけで ... >=> _bar(kf)_
M<T> M<A> this T _kf_ with M ⇔ ※ もう片方の Interface に関しては、ぜひ皆さまのお手元で探索まで 💪
次のような型 (と Interface) を考える: ``` ``` 候補:Chain の仕様 >=> interface
M<T> { ['fantasy-land/chain'](kf: (t: T) => M<A>): M<A>; } `M<T>` が Chain という代数的構造を満たすとしたら、任意のインスタンス `m` に対して: - `m['fantasy-land/chain'](f)['fantasy-land/chain'](g)` is equivalent to `m['fantasy-land/chain'](x => f(x)['fantasy-land/chain'](g))` ... このルールが成立する ⇒ `PromiseLike<T>` と `Result<T, E>` の 双方でルールが成立する なら、Chain として抽象化 できる!
Q. ところで、ルールの成立をどのように調べる ...?🤔
A. 数学で殴る 👊
現実案:Property-based Testing を用いる 宣言的な記述 にもとづいて、ランダムな入力パターンを自動生成しテストを行う 仕組みのこと TypeScript においては fast-check などのライブラリで実現できる
📝 【 代数的構造の現実的な確認手順 】 1. 型や Interface を観察し、共通化できそうかあたりを付ける 2. Fantasy Land を参照し、仕様の候補を洗い出す 3. Propety-based Testing を活用し、仕様を (大まかに) 満たせるか確認する >=>
Property-based Testing の実装例 (1) `Promise` そのままだと Interface を満たせないので、ラップした class を準備:
>=> class M<T> { private constructor(public readonly value: PromiseLike<T>) {} ['fantasy-land/chain']<A>(kf: (t: T) => M<A>): M<A> { return new M(this.value.then(t => kf(t).value)); } static of<T>(t: T): M<T> { return new M(Promise.resolve(t)); } }
Property-based Testing の実装例 (2) >=> Chain の仕様をもとにテストを作成 ( `Result` 版も同様な流れで作成できる
): const chainAssociativity = fc.asyncProperty( fc.integer(), async (x) => { const m = M.of(x); // f と g を動的に用意するとより精緻 const lhs = await m['fantasy-land/chain'](f)['fantasy-land/chain'](g).value; const rhs = await m['fantasy-land/chain'](x => f(x)['fantasy-land/chain'](g)).value; return lhs === rhs; }, ); await fc.assert(chainAssociativity, { numRuns: 100 });
実際どうなるか? 以下の条件のもと、`Promise` と `Result` は Chain として抽象化しても問題ない ✅: - `onrejected`
が実行されることのない `Promise` のみを用いる - 型定義が `(reason: any) => B | PromiseLike<B>` な時点で怪しさはあったが、実際ダメ 😇 - `Promise<Promise<T>>` については考えない - なぜならネストした `Promise` のインスタンスは そもそも作ることができない から 代数的構造に着目したおかげで、破綻の兆候を事前に検知 できたとも言える → より良い Interface の探索 にもつながる ( e.g. `() => Promise<Result<T, E>>` ) >=>
現在地点の確認 >=> `Promise` の型定義 `Result` の型定義 `Promise` の振る舞い `Result` の振る舞い
代数的構造の仕様 抽象化した型定義 抽象化した振る舞い 代数的構造 "Fantasy Land" 🧚 ✅ ✅ 𝑭𝒊𝒏.
α. TC39 Proposals による未来の姿
Fantasy Land の気になるところ class の利用を前提にしている こと 🤔 (※ class を絶対悪とは思っていません)
【 class の良いところ 】 - 🥳 戻り値を単一の class に閉じることで、メソッドチェーンによる見通しの良さが得られる - 🥳 class 自体が 1 つの名前空間として機能する 【 class の微妙なところ 】 - 🤔 Serialize と Deserialize に関する考慮が必要 - 🤔 不変クラスを徹底しないと、内部に持つ状態が不用意な複雑性を招きかねない >=>
e.g. 関数による実装 Currying Data-last Function を用いることで、関数合成がメソッドチェーン とみなせるが ... >=> const
data = [ { name: 'john', age: 20, gender: 'm' }, { name: 'marry', age: 22, gender: 'f' }, { name: 'samara', age: 24, gender: 'f' }, ]; R.pipe( data, R.filter((x) => x.gender === 'f'), R.groupBy((x) => x.age), ); data .filter((x) => x.gender === 'f') .groupBy((x) => x.age); - そのためだけにライブラリを導入するか?🤔 - 初見だと少し ギョッ としないか?🤔
A. それ、Call-this Operator なら便利になるよ 🚀
TC39:Call-this Operator ECMAScript Stage-1 Proposal として議論されているもの TypeScript 界隈だと @yukukotani さんが積極的にアウトプットされているので、ぜひチェックまで!🔍
>=> origin :https://speakerdeck.com/yukukotani/my-own-typescript-future
まとめ
- `Promise` と `Result` を例に、型や Interface を通じて相互の類似を考えた - 一方で、似ている からといって
必ずしも共通化できるとは限らない ことも確かめた - Fantasy Land (代数的構造 の仕様) は、そのような 共通化を紐解くヒント 【 さらに学ぶために 】 代数的構造は "データ構造" とも密接な関連を持つので、以下の記事も参考まで 📝 まとめ >=>