diff --git a/src/algebra/free.js b/src/algebra/free.js index ca81457..28c072b 100644 --- a/src/algebra/free.js +++ b/src/algebra/free.js @@ -2,10 +2,7 @@ import { Algebra, Foldable, Monad, Traversable } from './interfaces.js' import { curry } from '../..//vendor/izuna/src/index.js' import { Reducer } from './utilities.js' -/** @import { Applicative, ApplicativeTypeRef, Apply, Chain, Comonad, Foldable as FoldableT, Functor, Monad as MonadT, Morphism, Traversable as TraversableT } from './types.js' */ - - -/** @import { InferredMorphism } from './types.js' */ +/** @import { Applicative, ApplicativeTypeRef, Apply, Chain, Foldable as FoldableT, Functor, Morphism, Traversable as TraversableT } from './types.js' */ const kleisli = curry((f, g, x) => f(x).chain(g)) @@ -13,7 +10,6 @@ const kleisli = curry((f, g, x) => f(x).chain(g)) * @template T * @typedef {Pure | Impure} Free */ -const Free = {} /** @template T */ export class Pure extends Algebra(Monad, Traversable) { @@ -188,16 +184,15 @@ const pure = x => new Pure(x) */ const impure = (x, f) => new Impure(x, f) - /** * @template T * @param {T} x * @returns Impure */ export const liftF = x => impure(x, pure) -import { id, Identity } from './identity.js' -import { Option, some } from './option.js' -const a = liftF(1).chain(() => liftF(2)).reduce((acc, x) => acc + x, 0) -console.log(a) +const TypeRef = () => { } +TypeRef.constructor.of = pure + +export const Free = TypeRef diff --git a/src/algebra/option.js b/src/algebra/option.js index 60d8a21..314deb7 100644 --- a/src/algebra/option.js +++ b/src/algebra/option.js @@ -1,23 +1,16 @@ -import { Algebra, Foldable, Monad, Monoid, Setoid } from './interfaces.js' +import { Algebra, Foldable, Monad, Setoid } from './interfaces.js' /** @import { Morphism } from './types.js' */ +const Interfaces = Algebra(Setoid, Monad, Foldable) + /** * @template T - * @type {Some | None} Option + * @typedef {Some | None} Option */ -export class Option extends Algebra(Setoid, Monad, Foldable) { - /** - * @template T - * @param {T} value - */ - static of(value) { - return Some.of(value) - } -} /** @template T */ -export class Some extends Option { +export class Some extends Interfaces { /** @type {T} */ #value @@ -28,15 +21,6 @@ export class Some extends Option { this.#value = value } - /** - * @template T - * @param {T} value - * @returns {Some} - */ - static of(value) { - return new Some(value) - } - /** * @param {Option} other */ @@ -88,7 +72,7 @@ export class Some extends Option { } /** @template T */ -export class None extends Option { +export class None extends Interfaces { /** * @param {Option} other */ @@ -136,10 +120,6 @@ export class None extends Option { reduce(_f, init) { return init } - - empty() { - return Option.empty() - } } /** @@ -149,3 +129,9 @@ export class None extends Option { export const some = value => new Some(value) export const none = new None() +const TypeRef = some +TypeRef.constructor['of'] = some +TypeRef.constructor['zero'] = none + +export const Option = TypeRef + diff --git a/src/algebra/result.js b/src/algebra/result.js index da59344..f85dc75 100644 --- a/src/algebra/result.js +++ b/src/algebra/result.js @@ -1,26 +1,19 @@ -import { Algebra, Foldable, Monad, Setoid } from './interfaces.js' +import { id, Identity } from './identity.js' +import { Algebra, Bifunctor, Foldable, Monad, Setoid } from './interfaces.js' -/** @import { Morphism } from './types.js' */ +/** @import { Apply, Chain, Functor, Bifunctor as BifunctorT, Foldable as FoldableT, Morphism, Setoid as SetoidT } from './types.js' */ + +const Interfaces = Algebra(Setoid, Monad, Foldable, Bifunctor) /** * @template T, E - * @type {Ok | Err} Result + * @typedef {Ok | Err} Result */ -export class Result extends Algebra(Setoid, Monad, Foldable) { - /** - * @template T - * @param {T} value - * @returns {Ok} - */ - static of(value) { - return new Ok(value) - } -} /** * @template T, E */ -export class Ok extends Result { +export class Ok extends Interfaces { /** @type {T} */ #value @@ -35,11 +28,14 @@ export class Ok extends Result { } /** + * @type {SetoidT['equals']} * @param {Result} other + * @returns {boolean} */ equals(other) { - return other instanceof Ok && - other.chain(v => v === this.#value) + if (!(other instanceof Ok)) { return false } + const eq = other.chain(v => (id(v === this.#value))) + return /** @type {Identity} */ (eq).extract() } /** @returns {this is Ok} */ @@ -49,30 +45,38 @@ export class Ok extends Result { isErr() { return false } /** - * @template R - * @param {Morphism} f - * @this {Ok} - * @returns {R} + * @type {Chain['chain']} */ chain(f) { return f(this.#value) } /** - * @template R - * @param {Morphism} f - * @this {Ok} - * @returns {Ok} + * @template U + * @type {Functor['map']} + * @param {Morphism} f + * @returns {Functor} */ map(f) { - return Result.of(this.chain(f)) + return this.chain(v => ok(f(v))) } /** - * @template R - * @param {Morphism} f - * @this {Ok} - * @returns {Ok} + * @template U + * @type {Apply['ap']} + * @param {Apply>} b + * @returns {Result} + */ + ap(b) { + return /** @type {Result} */ (this.chain(v => + /** @type {Chain} */(b.map(f => f(v))) + )) + } + + /** + * @template U + * @borrows {Result~map} + * @param {Morphism} f */ then(f) { return this.map(f) @@ -89,6 +93,7 @@ export class Ok extends Result { /** * @template U + * @type {FoldableT['reduce']} * @param {(acc: U, value: T) => U} f * @param {U} init * @returns {U} @@ -101,7 +106,7 @@ export class Ok extends Result { /** * @template T, E */ -export class Err extends Result { +export class Err extends Interfaces { /** @type {E} */ #value @@ -115,12 +120,16 @@ export class Err extends Result { this.#value = value } + /** - * @param {Result} other + * @type {SetoidT['equals']} + * @param {Err} other + * @returns {boolean} */ equals(other) { - return other instanceof Err && - other.chain(v => v === this.#value) + if (!(other instanceof Err)) { return false } + const eq = other.catch(v => (id(v === this.#value))) + return /** @type {Identity} */ (eq).extract() } /** @returns {this is Ok} */ @@ -190,3 +199,7 @@ export const ok = v => new Ok(v) */ export const err = e => new Err(e) +const TypeRef = ok +TypeRef.constructor['of'] = ok +TypeRef.constructor['zero'] = err +