change type ref pattern; update type signatures

This commit is contained in:
Rowan 2025-04-12 02:28:18 -05:00
parent 19f02031b0
commit cafa3a8fa7
7 changed files with 199 additions and 72 deletions

View file

@ -64,7 +64,7 @@ export class Pure extends Algebra(Monad, Traversable) {
* @returns {Applicative<Free<U>>} * @returns {Applicative<Free<U>>}
*/ */
traverse(_A, f) { traverse(_A, f) {
return f(this.#value).map(pure) return /** @type {Applicative<Free<U>>} */ (f(this.#value).map(pure))
} }
run() { run() {
@ -157,9 +157,9 @@ export class Impure extends Algebra(Monad, Foldable, Traversable) {
const rest = next.traverse(A, f) const rest = next.traverse(A, f)
return /** @type {Applicative<Free<U>>} */ (rest.ap( return /** @type {Applicative<Free<U>>} */ (rest.ap(
fb.map(b => next => impure(b, () => /** @type {Apply<Morphism<TraversableT<U>, U>>} */(fb.map(b => next => impure(b, () =>
/** @type {Free<U>} */(next) /** @type {Free<U>} */(next)
)) )))
)) ))
} }
} }

View file

@ -1,6 +1,6 @@
import { Algebra, Comonad, Monad } from './interfaces.js' import { Algebra, Comonad, Monad } from './interfaces.js'
/** @import { Apply, Morphism } from './types.js' */ /** @import { Apply, Functor, Morphism } from './types.js' */
/** @template T */ /** @template T */
export class Identity extends Algebra(Monad, Comonad) { export class Identity extends Algebra(Monad, Comonad) {
@ -25,10 +25,11 @@ export class Identity extends Algebra(Monad, Comonad) {
/** /**
* @template U * @template U
* @type {Functor<T>['map']}
* @param {Morphism<T, U>} f * @param {Morphism<T, U>} f
* @returns {Identity<U>}
*/ */
map(f) { map(f) {
console.log(this.toString(), f.toString())
return id(f(this.#value)) 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) export const id = value => new Identity(value)

View file

@ -1,6 +1,6 @@
import { Algebra, Monad } from './interfaces.js' 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 */ /** @template {Fn} T */
export class IO extends Algebra(Monad) { export class IO extends Algebra(Monad) {
@ -23,26 +23,33 @@ export class IO extends Algebra(Monad) {
} }
/** /**
* @param {InferredMorphism<T>} f * @template {Fn} U
* @type {Chain<T>['chain']}
* @param {Morphism<T, IO<U>>} f
* @returns {IO<U>}
*/ */
chain(f) { chain(f) {
return IO.of(() => f(this.run()).run()) return /** @type {IO<U>} */ (IO.of(() => f(this.run()).run()))
}
/**
* @param {InferredMorphism<T>} f
*/
map(f) {
return IO.of(() => f(this.run()))
} }
/** /**
* @template {Fn} U * @template {Fn} U
* @type {Functor<T>['map']}
* @param {Morphism<T, U>} f
* @returns {IO<U>}
*/
map(f) {
return /** @type {IO<U>} */ (IO.of(() => f(this.run())))
}
/**
* @template {Fn} U
* @type {Apply<T>['ap']}
* @param {IO<Morphism<T, U>>} other * @param {IO<Morphism<T, U>>} other
* @returns {IO<T>} * @returns {IO<U>}
*/ */
ap(other) { ap(other) {
return /** @type {IO<T>} */ (IO.of((() => other.run()(this.run())))) return /** @type {IO<U>} */ (IO.of((() => other.run()(this.run()))))
} }
run() { run() {

View file

@ -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 * @template T
@ -22,39 +23,53 @@ export class Some extends Interfaces {
} }
/** /**
* @param {Option<T>} other * @type {SetoidT<T>['equals']}
* @param {Some<T>} other
*/ */
equals(other) { equals(other) {
return other instanceof Some && if (other instanceof Some) { return false }
other.chain(v => v === this.#value) const eq = /** @type {Some<T>} */ (other).chain(v => id(v === this.#value))
} return /** @type {Identity<boolean>} */ (eq).extract()
ap(b) {
return b.chain(f => this.map(f))
} }
/** /**
* @template R * @template U
* @param {Morphism<T, R>} f * @type {Apply<T>['ap']}
* @returns {R} * @param {Some<Morphism<T, U>>} b
* @returns {Some<U>}
*/
ap(b) {
return /** @type {Some<U>} */ (b.chain(f =>
/** @type {Some<U>} */(this.map(f))
))
}
/**
* @type {Alt<T>['alt']}
*/
alt(b) {
return this
}
/**
* @type {Chain<T>['chain']}
*/ */
chain(f) { chain(f) {
return f(this.#value) return f(this.#value)
} }
/** /**
* @template R * @template U
* @param {Morphism<T, R>} f * @type {Functor<T>['map']}
* @returns {Some<R>} * @param {Morphism<T, U>} f
* @returns {Some<U>}
*/ */
map(f) { map(f) {
return Some.of(this.chain(f)) return /** @type {Some<U>} */ (this.chain(v => some(f(v))))
} }
/** /**
* @template R * @type {Functor<T>['map']}
* @param {Morphism<T, R>} f
* @returns {Some<R>}
*/ */
then(f) { then(f) {
return this.map(f) return this.map(f)
@ -62,6 +77,7 @@ export class Some extends Interfaces {
/** /**
* @template U * @template U
* @type {FoldableT<T>['reduce']}
* @param {(acc: U, value: T) => U} f * @param {(acc: U, value: T) => U} f
* @param {U} init * @param {U} init
* @returns {U} * @returns {U}
@ -74,29 +90,42 @@ export class Some extends Interfaces {
/** @template T */ /** @template T */
export class None extends Interfaces { export class None extends Interfaces {
/** /**
* @param {Option<T>} other * @type {SetoidT<T>['equals']}
*/ */
equals(other) { equals(other) {
return other === none return other === none
} }
/**
* @type {Apply<T>['ap']}
* @returns {this}
*/
ap(_b) { ap(_b) {
return this return this
} }
/** /**
* @template R * @type {Alt<T>['alt']}
* @param {Morphism<T, R>} _f */
* @returns {None} alt(b) {
return b
}
/**
* @template U
* @type {Chain<T>['chain']}
* @param {Morphism<T, U>} _f
* @returns {this}
*/ */
chain(_f) { chain(_f) {
return this return this
} }
/** /**
* @template R * @template U
* @param {Morphism<T, R>} _f * @type {Functor<T>['map']}
* @returns {None} * @param {Morphism<T, U>} _f
* @returns {this}
*/ */
map(_f) { map(_f) {
return this return this
@ -104,6 +133,7 @@ export class None extends Interfaces {
/** /**
* @template R * @template R
* @type {Functor<T>['map']}
* @param {Morphism<T, R>} _f * @param {Morphism<T, R>} _f
* @returns {None} * @returns {None}
*/ */
@ -113,6 +143,7 @@ export class None extends Interfaces {
/** /**
* @template U * @template U
* @type {FoldableT<T>['reduce']}
* @param {(acc: U, value: T) => U} _f * @param {(acc: U, value: T) => U} _f
* @param {U} init * @param {U} init
* @returns {U} * @returns {U}

View file

@ -1,7 +1,7 @@
import { id } from '../../vendor/izuna/src/index.js' import { id } from '../../vendor/izuna/src/index.js'
import { Algebra, Monad } from './interfaces.js' import { Algebra, Monad } from './interfaces.js'
/** @import { InferredMorphism, Morphism } from './types.js' */ /** @import { Apply, Chain, Functor, InferredMorphism, Morphism } from './types.js' */
/** /**
* @template T * @template T
@ -34,14 +34,17 @@ export class Reader extends Algebra(Monad) {
} }
/** /**
* @param {InferredMorphism<T>} f * @template U
* @returns {Reader<T>} * @type {Functor<T>['map']}
* @param {Morphism<T, U>} f
* @returns {Reader<U>}
*/ */
map(f) { map(f) {
return new Reader(/** @type {InferredMorphism<T>} */(env => f(this.#run(env)))) return new Reader(env => f(this.#run(env)))
} }
/** /**
* @type {Chain<T>['chain']}
* @param {InferredMorphism<T>} f * @param {InferredMorphism<T>} f
* @returns {Reader<T>} * @returns {Reader<T>}
*/ */
@ -50,14 +53,13 @@ export class Reader extends Algebra(Monad) {
} }
/** /**
* @template R * @template U
* @param {Reader<(v: T) => R>} other * @type {Apply<T>['ap']}
* @returns {Reader<R>} * @param {Reader<Morphism<T, U>>} other
* @returns {Reader<U>}
*/ */
ap(other) { ap(other) {
return new Reader( return new Reader(
// FIXME: type errors
// @ts-ignore
env => other.run(env)(this.run(env)) env => other.run(env)(this.run(env))
) )
} }
@ -71,9 +73,9 @@ export class Reader extends Algebra(Monad) {
} }
/** /**
* @template R * @template U
* @param {T} env * @param {T} env
* @returns {R} * @returns {U}
*/ */
run(env) { run(env) {
return this.#run(env) return this.#run(env)

View file

@ -1,9 +1,9 @@
import { id, Identity } from './identity.js' 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 * @template T, E
@ -51,6 +51,16 @@ export class Ok extends Interfaces {
return f(this.#value) return f(this.#value)
} }
/**
* @template E2
* @type {Chain<E>['chain']}
* @param {Morphism<E, E2>} _f
* @returns {this}
*/
chainErr(_f) {
return this
}
/** /**
* @template U * @template U
* @type {Functor<T>['map']} * @type {Functor<T>['map']}
@ -61,6 +71,17 @@ export class Ok extends Interfaces {
return this.chain(v => ok(f(v))) return this.chain(v => ok(f(v)))
} }
/**
* @template E2
* @type {Functor<E>['map']}
* @this {Result<T, E>}
* @param {Morphism<E, E2>} _f
* @returns {Result<T, E2>}
*/
mapErr(_f) {
return /** @type {never} */ (this)
}
/** /**
* @template U * @template U
* @type {Apply<T>['ap']} * @type {Apply<T>['ap']}
@ -73,6 +94,13 @@ export class Ok extends Interfaces {
)) ))
} }
/**
* @type Alt<T>['alt']
*/
alt(_b) {
return this
}
/** /**
* @template U * @template U
* @borrows {Result~map} * @borrows {Result~map}
@ -101,6 +129,17 @@ export class Ok extends Interfaces {
reduce(f, init) { reduce(f, init) {
return f(init, this.#value) return f(init, this.#value)
} }
/**
* @template T2, E2
* @type {BifunctorT<T, E>['bimap']}
* @param {Morphism<T, T2>} f
* @param {Morphism<E, E2>} _g
* @returns {Result<T2, E2>}
*/
bimap(f, _g) {
return /** @type {Result<T2, E2>} */ (this.map(f))
}
} }
/** /**
@ -110,7 +149,6 @@ export class Err extends Interfaces {
/** @type {E} */ /** @type {E} */
#value #value
/** /**
* @param {E} value * @param {E} value
* @constructs {Err<T, E>} * @constructs {Err<T, E>}
@ -120,7 +158,6 @@ export class Err extends Interfaces {
this.#value = value this.#value = value
} }
/** /**
* @type {SetoidT<T>['equals']} * @type {SetoidT<T>['equals']}
* @param {Err<T, E>} other * @param {Err<T, E>} other
@ -128,7 +165,7 @@ export class Err extends Interfaces {
*/ */
equals(other) { equals(other) {
if (!(other instanceof Err)) { return false } 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<boolean>} */ (eq).extract() return /** @type {Identity<boolean>} */ (eq).extract()
} }
@ -139,8 +176,7 @@ export class Err extends Interfaces {
isErr() { return true } isErr() { return true }
/** /**
* @template R * @type {Chain<T>['chain']}
* @param {Morphism<T, R>} _f
* @returns {this} * @returns {this}
*/ */
chain(_f) { chain(_f) {
@ -148,8 +184,17 @@ export class Err extends Interfaces {
} }
/** /**
* @template R * @template E2
* @param {Morphism<T, R>} _f * @type {Chain<E>['chain']}
* @param {Morphism<E, Result<T, E2>>} f
* @returns {Result<T, E2>}
*/
chainErr(f) {
return f(this.#value)
}
/**
* @type {Functor<T>['map']}
* @returns {this} * @returns {this}
*/ */
map(_f) { map(_f) {
@ -157,8 +202,17 @@ export class Err extends Interfaces {
} }
/** /**
* @template R * @template E2
* @param {Morphism<T, R>} _f * @type {Functor<E>['map']}
* @param {Morphism<E, E2>} f
* @returns {Result<T, E2>}
*/
mapErr(f) {
return /** @type {Result<T, E2>} */ (this.bimap(id, f))
}
/**
* @type {Functor<T>['map']}
* @returns {this} * @returns {this}
*/ */
then(_f) { then(_f) {
@ -167,6 +221,7 @@ export class Err extends Interfaces {
/** /**
* @template R * @template R
* @type {Functor<E>['map']}
* @param {Morphism<E, R>} f * @param {Morphism<E, R>} f
* @returns {Err<T, R>} * @returns {Err<T, R>}
*/ */
@ -174,8 +229,16 @@ export class Err extends Interfaces {
return new Err(f(this.#value)) return new Err(f(this.#value))
} }
/**
* @type Alt<T>['alt']
*/
alt(b) {
return b
}
/** /**
* @template U * @template U
* @type {FoldableT<T>['reduce']}
* @param {(acc: U, value: T) => U} _f * @param {(acc: U, value: T) => U} _f
* @param {U} init * @param {U} init
* @returns {U} * @returns {U}
@ -183,6 +246,17 @@ export class Err extends Interfaces {
reduce(_f, init) { reduce(_f, init) {
return init return init
} }
/**
* @template T2, E2
* @type {BifunctorT<T, E>['bimap']}
* @param {Morphism<T, T2>} _f
* @param {Morphism<E, E2>} g
* @returns {Result<T2, E2>}
*/
bimap(_f, g) {
return /** @type {Result<T2, E2>} */ (err(g(this.#value)))
}
} }
/** /**

View file

@ -108,10 +108,10 @@ export default {}
/** /**
* @template T * @template T
* @typedef {{ * @typedef {
ap: <U>(b: Applicative<Morphism<U, T>>) => Applicative<T>, Functor<T> &
map: <U>(f: Morphism<T, U>) => Applicative<U> Apply<T>
* }} Applicative * } Applicative
*/ */
/** /**
@ -210,5 +210,13 @@ export default {}
* } Comonad<T> * } Comonad<T>
*/ */
/**
* @template A, X
* @typedef {
Functor<A> &
{ bimap: <B, Y>(f: Morphism<A, B>, g: Morphism<X, Y>) => Bifunctor<B, Y> }
* } Bifunctor
*/
/** @typedef {(...args: any[]) => any} Fn */ /** @typedef {(...args: any[]) => any} Fn */