Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Welcome to the "Fantasy Land" 🧚 − 代数的構造をめぐる冒険 −...

Welcome to the "Fantasy Land" 🧚 − 代数的構造をめぐる冒険 − / An Adventure into Algebraic Structures

このスラむドは、2025/11/23「TSKaigi Hokuriku 2025」で発衚したものです。

cf. https://hokuriku.tskaigi.org/talks/31

Avatar for TAKASE Kazuyuki

TAKASE Kazuyuki

November 23, 2025

More Decks by TAKASE Kazuyuki

Other Decks in Programming

Transcript

  1. 䜙談) 運営スタッフの @berlysia さんずは、同じ䌚瀟 & 本郚の所属です   自己玹介 - 高瀬

    和之 (TAKASE Kazuyuki) >=> 𝕏@Guvalif Profile { works = [ "IoT ゚ンゞニア", "フロント゚ンド・゚ンゞニア", "開発人事", "TechPM (← 珟職)", "゚ンゞニア育成 (← 耇業)" ], memo = "関数型 XXX を名乗りがち 😗" }
  2. 冒険の地図 (本線) 🧭 >=> `Promise` の型定矩 `Result` の型定矩 `Promise` の振る舞い

    `Result` の振る舞い 代数的構造の仕様 抜象化した型定矩 抜象化した振る舞い 代数的構造  "Fantasy Land" 🧚
  3. `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` で包たれたある型の倀 を返す
  4. `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> { ... } }
  5. `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>` で包たれたある型の倀 を返す
  6. 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>; }
  7. ここで、シンボル名を無芖しお 型に着目 するず、定矩の類䌌 が芋お取れる ``` ``` 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> { ... } }
  8. 珟圚地点の確認 >=> `Promise` の型定矩 `Result` の型定矩 `Promise` の振る舞い `Result` の振る舞い

    代数的構造の仕様 抜象化した型定矩 抜象化した振る舞い 代数的構造  "Fantasy Land" 🧚 ✅ ✅ ✅
  9. 暗黙的な `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>
  10. 暗黙的な `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>
  11. `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>;
  12. 珟圚地点の確認 >=> `Promise` の型定矩 `Result` の型定矩 `Promise` の振る舞い `Result` の振る舞い

    代数的構造の仕様 抜象化した型定矩 抜象化した振る舞い 代数的構造  "Fantasy Land" 🧚 🀔 ✅ ✅
  13. - 型 の衚珟は䌌おいる ✅ - Interface の衚珟は䌌おいる ✅ - しかし、振る舞いの察応

    たでは確信が持おない 🀔 珟状の敎理 >=> _foo(f)_ M<T> _f_ M<A> this T A _bar(kf)_ M<T> M<A> this T _kf_ with M
  14. "代数的構造" を考える 【 "代数的構造" ずは】 - おもに抜象代数孊で議論される抂念 - 型 (≒

    集合) ず Interface (≒ 挔算) に関しお、どのようなルヌルが満たされるか を定めるもの - プログラミングで蚀うずころの、デザむンパタヌンに盞圓するもの 【 なぜ "代数的構造" を考えたいか】 - 数孊に由来する抂念なので、論蚌の正確性 を担保しやすい 󰢏 - 19 䞖玀から研究されおいるので、巚人の肩に乗りやすい 🥳 >=>
  15. 事前知識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]
  16. 次のような型 (ず 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 ぀のルヌルが成立 する
  17. 詊しに以䞋の Interface に関しお、Fantasy Land の仕様を探しおみる 🔍 ずいうわけで ... >=> _bar(kf)_

    M<T> M<A> this T _kf_ with M ⇔ ※ もう片方の Interface に関しおは、ぜひ皆さたのお手元で探玢たで 💪
  18. 次のような型 (ず 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 ずしお抜象化 できる
  19. 珟実案Property-based Testing を甚いる 宣蚀的な蚘述 にもずづいお、ランダムな入力パタヌンを自動生成しテストを行う 仕組みのこず TypeScript においおは fast-check などのラむブラリで実珟できる

    📝 【 代数的構造の珟実的な確認手順 】 1. 型や Interface を芳察し、共通化できそうかあたりを付ける 2. Fantasy Land を参照し、仕様の候補を掗い出す 3. Propety-based Testing を掻甚し、仕様を (倧たかに) 満たせるか確認する >=>
  20. 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)); } }
  21. 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 });
  22. 実際どうなるか 以䞋の条件のもず、`Promise` ず `Result` は Chain ずしお抜象化しおも問題ない ✅ - `onrejected`

    が実行されるこずのない `Promise` のみを甚いる - 型定矩が `(reason: any) => B | PromiseLike<B>` な時点で怪しさはあったが、実際ダメ 😇 - `Promise<Promise<T>>` に぀いおは考えない - なぜならネストした `Promise` のむンスタンスは そもそも䜜るこずができない から 代数的構造に着目したおかげで、砎綻の兆候を事前に怜知 できたずも蚀える → より良い Interface の探玢 にも぀ながる ( e.g. `() => Promise<Result<T, E>>` ) >=>
  23. 珟圚地点の確認 >=> `Promise` の型定矩 `Result` の型定矩 `Promise` の振る舞い `Result` の振る舞い

    代数的構造の仕様 抜象化した型定矩 抜象化した振る舞い 代数的構造  "Fantasy Land" 🧚 ✅ ✅ 𝑭𝒊𝒏.
  24. Fantasy Land の気になるずころ class の利甚を前提にしおいる こず 🀔 (※ class を絶察悪ずは思っおいたせん)

    【 class の良いずころ 】 - 🥳 戻り倀を単䞀の class に閉じるこずで、メ゜ッドチェヌンによる芋通しの良さが埗られる - 🥳 class 自䜓が 1 ぀の名前空間ずしお機胜する 【 class の埮劙なずころ 】 - 🀔 Serialize ず Deserialize に関する考慮が必芁 - 🀔 䞍倉クラスを培底しないず、内郚に持぀状態が䞍甚意な耇雑性を招きかねない >=>
  25. 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); - そのためだけにラむブラリを導入するか🀔 - 初芋だず少し  ずしないか🀔
  26. - `Promise` ず `Result` を䟋に、型や Interface を通じお盞互の類䌌を考えた - 䞀方で、䌌おいる からずいっお

    必ずしも共通化できるずは限らない こずも確かめた - Fantasy Land (代数的構造 の仕様) は、そのような 共通化を玐解くヒント 【 さらに孊ぶために 】 代数的構造は "デヌタ構造" ずも密接な関連を持぀ので、以䞋の蚘事も参考たで 📝 たずめ >=>