From cafa3a8fa777ab294e0674ae2ee364da6d85db7f Mon Sep 17 00:00:00 2001 From: rowan Date: Sat, 12 Apr 2025 02:28:18 -0500 Subject: [PATCH] change type ref pattern; update type signatures --- src/algebra/free.js | 8 ++-- src/algebra/identity.js | 9 +++- src/algebra/io.js | 31 ++++++++----- src/algebra/option.js | 85 +++++++++++++++++++++++------------ src/algebra/reader.js | 24 +++++----- src/algebra/result.js | 98 ++++++++++++++++++++++++++++++++++++----- src/algebra/types.js | 16 +++++-- 7 files changed, 199 insertions(+), 72 deletions(-) diff --git a/src/algebra/free.js b/src/algebra/free.js index 28c072b..faad1e4 100644 --- a/src/algebra/free.js +++ b/src/algebra/free.js @@ -64,7 +64,7 @@ export class Pure extends Algebra(Monad, Traversable) { * @returns {Applicative>} */ traverse(_A, f) { - return f(this.#value).map(pure) + return /** @type {Applicative>} */ (f(this.#value).map(pure)) } run() { @@ -157,9 +157,9 @@ export class Impure extends Algebra(Monad, Foldable, Traversable) { const rest = next.traverse(A, f) return /** @type {Applicative>} */ (rest.ap( - fb.map(b => next => impure(b, () => - /** @type {Free} */(next) - )) + /** @type {Apply, U>>} */(fb.map(b => next => impure(b, () => + /** @type {Free} */(next) + ))) )) } } diff --git a/src/algebra/identity.js b/src/algebra/identity.js index efba1b3..538e0dd 100644 --- a/src/algebra/identity.js +++ b/src/algebra/identity.js @@ -1,6 +1,6 @@ import { Algebra, Comonad, Monad } from './interfaces.js' -/** @import { Apply, Morphism } from './types.js' */ +/** @import { Apply, Functor, Morphism } from './types.js' */ /** @template T */ export class Identity extends Algebra(Monad, Comonad) { @@ -25,10 +25,11 @@ export class Identity extends Algebra(Monad, Comonad) { /** * @template U + * @type {Functor['map']} * @param {Morphism} f + * @returns {Identity} */ map(f) { - console.log(this.toString(), f.toString()) return id(f(this.#value)) } @@ -66,5 +67,9 @@ export class Identity extends Algebra(Monad, Comonad) { } } +/** + * @template T + * @param {T} value + */ export const id = value => new Identity(value) diff --git a/src/algebra/io.js b/src/algebra/io.js index 3061f4a..8204528 100644 --- a/src/algebra/io.js +++ b/src/algebra/io.js @@ -1,6 +1,6 @@ import { Algebra, Monad } from './interfaces.js' -/** @import { Fn, InferredMorphism, Morphism } from './types.js' */ +/** @import { Apply, Chain, Fn, Functor, InferredMorphism, Morphism } from './types.js' */ /** @template {Fn} T */ export class IO extends Algebra(Monad) { @@ -23,26 +23,33 @@ export class IO extends Algebra(Monad) { } /** - * @param {InferredMorphism} f + * @template {Fn} U + * @type {Chain['chain']} + * @param {Morphism>} f + * @returns {IO} */ chain(f) { - return IO.of(() => f(this.run()).run()) - } - - /** - * @param {InferredMorphism} f - */ - map(f) { - return IO.of(() => f(this.run())) + return /** @type {IO} */ (IO.of(() => f(this.run()).run())) } /** * @template {Fn} U + * @type {Functor['map']} + * @param {Morphism} f + * @returns {IO} + */ + map(f) { + return /** @type {IO} */ (IO.of(() => f(this.run()))) + } + + /** + * @template {Fn} U + * @type {Apply['ap']} * @param {IO>} other - * @returns {IO} + * @returns {IO} */ ap(other) { - return /** @type {IO} */ (IO.of((() => other.run()(this.run())))) + return /** @type {IO} */ (IO.of((() => other.run()(this.run())))) } run() { diff --git a/src/algebra/option.js b/src/algebra/option.js index 314deb7..7ebf79c 100644 --- a/src/algebra/option.js +++ b/src/algebra/option.js @@ -1,8 +1,9 @@ -import { Algebra, Foldable, Monad, Setoid } from './interfaces.js' +import { id, Identity } from './identity.js' +import { Algebra, Alternative, Foldable, Monad, Setoid } from './interfaces.js' -/** @import { Morphism } from './types.js' */ +/** @import { Alt, Apply, Chain, Foldable as FoldableT, Functor, Morphism, Setoid as SetoidT } from './types.js' */ -const Interfaces = Algebra(Setoid, Monad, Foldable) +const Interfaces = Algebra(Setoid, Alternative, Monad, Foldable) /** * @template T @@ -22,39 +23,53 @@ export class Some extends Interfaces { } /** - * @param {Option} other + * @type {SetoidT['equals']} + * @param {Some} other */ equals(other) { - return other instanceof Some && - other.chain(v => v === this.#value) - } - - ap(b) { - return b.chain(f => this.map(f)) + if (other instanceof Some) { return false } + const eq = /** @type {Some} */ (other).chain(v => id(v === this.#value)) + return /** @type {Identity} */ (eq).extract() } /** - * @template R - * @param {Morphism} f - * @returns {R} + * @template U + * @type {Apply['ap']} + * @param {Some>} b + * @returns {Some} + */ + ap(b) { + return /** @type {Some} */ (b.chain(f => + /** @type {Some} */(this.map(f)) + )) + } + + /** + * @type {Alt['alt']} + */ + alt(b) { + return this + } + + /** + * @type {Chain['chain']} */ chain(f) { return f(this.#value) } /** - * @template R - * @param {Morphism} f - * @returns {Some} + * @template U + * @type {Functor['map']} + * @param {Morphism} f + * @returns {Some} */ map(f) { - return Some.of(this.chain(f)) + return /** @type {Some} */ (this.chain(v => some(f(v)))) } /** - * @template R - * @param {Morphism} f - * @returns {Some} + * @type {Functor['map']} */ then(f) { return this.map(f) @@ -62,6 +77,7 @@ export class Some extends Interfaces { /** * @template U + * @type {FoldableT['reduce']} * @param {(acc: U, value: T) => U} f * @param {U} init * @returns {U} @@ -74,29 +90,42 @@ export class Some extends Interfaces { /** @template T */ export class None extends Interfaces { /** - * @param {Option} other + * @type {SetoidT['equals']} */ equals(other) { return other === none } + /** + * @type {Apply['ap']} + * @returns {this} + */ ap(_b) { return this } /** - * @template R - * @param {Morphism} _f - * @returns {None} + * @type {Alt['alt']} + */ + alt(b) { + return b + } + + /** + * @template U + * @type {Chain['chain']} + * @param {Morphism} _f + * @returns {this} */ chain(_f) { return this } /** - * @template R - * @param {Morphism} _f - * @returns {None} + * @template U + * @type {Functor['map']} + * @param {Morphism} _f + * @returns {this} */ map(_f) { return this @@ -104,6 +133,7 @@ export class None extends Interfaces { /** * @template R + * @type {Functor['map']} * @param {Morphism} _f * @returns {None} */ @@ -113,6 +143,7 @@ export class None extends Interfaces { /** * @template U + * @type {FoldableT['reduce']} * @param {(acc: U, value: T) => U} _f * @param {U} init * @returns {U} diff --git a/src/algebra/reader.js b/src/algebra/reader.js index c3d4c6c..617584e 100644 --- a/src/algebra/reader.js +++ b/src/algebra/reader.js @@ -1,7 +1,7 @@ import { id } from '../../vendor/izuna/src/index.js' import { Algebra, Monad } from './interfaces.js' -/** @import { InferredMorphism, Morphism } from './types.js' */ +/** @import { Apply, Chain, Functor, InferredMorphism, Morphism } from './types.js' */ /** * @template T @@ -34,14 +34,17 @@ export class Reader extends Algebra(Monad) { } /** - * @param {InferredMorphism} f - * @returns {Reader} + * @template U + * @type {Functor['map']} + * @param {Morphism} f + * @returns {Reader} */ map(f) { - return new Reader(/** @type {InferredMorphism} */(env => f(this.#run(env)))) + return new Reader(env => f(this.#run(env))) } /** + * @type {Chain['chain']} * @param {InferredMorphism} f * @returns {Reader} */ @@ -50,14 +53,13 @@ export class Reader extends Algebra(Monad) { } /** - * @template R - * @param {Reader<(v: T) => R>} other - * @returns {Reader} + * @template U + * @type {Apply['ap']} + * @param {Reader>} other + * @returns {Reader} */ ap(other) { return new Reader( - // FIXME: type errors - // @ts-ignore env => other.run(env)(this.run(env)) ) } @@ -71,9 +73,9 @@ export class Reader extends Algebra(Monad) { } /** - * @template R + * @template U * @param {T} env - * @returns {R} + * @returns {U} */ run(env) { return this.#run(env) diff --git a/src/algebra/result.js b/src/algebra/result.js index f85dc75..1445f3b 100644 --- a/src/algebra/result.js +++ b/src/algebra/result.js @@ -1,9 +1,9 @@ import { id, Identity } from './identity.js' -import { Algebra, Bifunctor, Foldable, Monad, Setoid } from './interfaces.js' +import { Algebra, Alternative, Bifunctor, Foldable, Monad, Setoid } from './interfaces.js' -/** @import { Apply, Chain, Functor, Bifunctor as BifunctorT, Foldable as FoldableT, Morphism, Setoid as SetoidT } from './types.js' */ +/** @import { Alt, Apply, Chain, Functor, Bifunctor as BifunctorT, Foldable as FoldableT, Morphism, Setoid as SetoidT } from './types.js' */ -const Interfaces = Algebra(Setoid, Monad, Foldable, Bifunctor) +const Interfaces = Algebra(Setoid, Alternative, Monad, Foldable, Bifunctor) /** * @template T, E @@ -51,6 +51,16 @@ export class Ok extends Interfaces { return f(this.#value) } + /** + * @template E2 + * @type {Chain['chain']} + * @param {Morphism} _f + * @returns {this} + */ + chainErr(_f) { + return this + } + /** * @template U * @type {Functor['map']} @@ -61,6 +71,17 @@ export class Ok extends Interfaces { return this.chain(v => ok(f(v))) } + /** + * @template E2 + * @type {Functor['map']} + * @this {Result} + * @param {Morphism} _f + * @returns {Result} + */ + mapErr(_f) { + return /** @type {never} */ (this) + } + /** * @template U * @type {Apply['ap']} @@ -73,6 +94,13 @@ export class Ok extends Interfaces { )) } + /** + * @type Alt['alt'] + */ + alt(_b) { + return this + } + /** * @template U * @borrows {Result~map} @@ -101,6 +129,17 @@ export class Ok extends Interfaces { reduce(f, init) { return f(init, this.#value) } + + /** + * @template T2, E2 + * @type {BifunctorT['bimap']} + * @param {Morphism} f + * @param {Morphism} _g + * @returns {Result} + */ + bimap(f, _g) { + return /** @type {Result} */ (this.map(f)) + } } /** @@ -110,7 +149,6 @@ export class Err extends Interfaces { /** @type {E} */ #value - /** * @param {E} value * @constructs {Err} @@ -120,7 +158,6 @@ export class Err extends Interfaces { this.#value = value } - /** * @type {SetoidT['equals']} * @param {Err} other @@ -128,7 +165,7 @@ export class Err extends Interfaces { */ equals(other) { if (!(other instanceof Err)) { return false } - const eq = other.catch(v => (id(v === this.#value))) + const eq = other.chainErr(v => id(v === this.#value)) return /** @type {Identity} */ (eq).extract() } @@ -139,8 +176,7 @@ export class Err extends Interfaces { isErr() { return true } /** - * @template R - * @param {Morphism} _f + * @type {Chain['chain']} * @returns {this} */ chain(_f) { @@ -148,8 +184,17 @@ export class Err extends Interfaces { } /** - * @template R - * @param {Morphism} _f + * @template E2 + * @type {Chain['chain']} + * @param {Morphism>} f + * @returns {Result} + */ + chainErr(f) { + return f(this.#value) + } + + /** + * @type {Functor['map']} * @returns {this} */ map(_f) { @@ -157,8 +202,17 @@ export class Err extends Interfaces { } /** - * @template R - * @param {Morphism} _f + * @template E2 + * @type {Functor['map']} + * @param {Morphism} f + * @returns {Result} + */ + mapErr(f) { + return /** @type {Result} */ (this.bimap(id, f)) + } + + /** + * @type {Functor['map']} * @returns {this} */ then(_f) { @@ -167,6 +221,7 @@ export class Err extends Interfaces { /** * @template R + * @type {Functor['map']} * @param {Morphism} f * @returns {Err} */ @@ -174,8 +229,16 @@ export class Err extends Interfaces { return new Err(f(this.#value)) } + /** + * @type Alt['alt'] + */ + alt(b) { + return b + } + /** * @template U + * @type {FoldableT['reduce']} * @param {(acc: U, value: T) => U} _f * @param {U} init * @returns {U} @@ -183,6 +246,17 @@ export class Err extends Interfaces { reduce(_f, init) { return init } + + /** + * @template T2, E2 + * @type {BifunctorT['bimap']} + * @param {Morphism} _f + * @param {Morphism} g + * @returns {Result} + */ + bimap(_f, g) { + return /** @type {Result} */ (err(g(this.#value))) + } } /** diff --git a/src/algebra/types.js b/src/algebra/types.js index 9378ddf..550e1ad 100644 --- a/src/algebra/types.js +++ b/src/algebra/types.js @@ -108,10 +108,10 @@ export default {} /** * @template T - * @typedef {{ - ap: (b: Applicative>) => Applicative, - map: (f: Morphism) => Applicative - * }} Applicative + * @typedef { + Functor & + Apply + * } Applicative */ /** @@ -210,5 +210,13 @@ export default {} * } Comonad */ +/** + * @template A, X + * @typedef { + Functor & + { bimap: (f: Morphism, g: Morphism) => Bifunctor } + * } Bifunctor + */ + /** @typedef {(...args: any[]) => any} Fn */