diff --git a/src/algebra/free.js b/src/algebra/free.js index bb68f07..be54b1e 100644 --- a/src/algebra/free.js +++ b/src/algebra/free.js @@ -1,5 +1,5 @@ import { liftF } from './fn.js' -import { Algebra, BaseSet, Comonad, Monad } from './index.js' +import { Algebra, BaseSet, Monad, Semigroupoid } from './index.js' /** @import { InferredMorphism, Morphism } from './types.js' */ @@ -8,7 +8,7 @@ import { Algebra, BaseSet, Comonad, Monad } from './index.js' * @extends BaseSet * @mixes Monad */ -export class Suspend extends Algebra(Monad) { +export class Suspend extends Algebra(Semigroupoid, Monad) { _value #fn @@ -55,6 +55,14 @@ export class Suspend extends Algebra(Monad) { return this.map(g) } + /** + * @template T + * @param {InferredMorphism} other + */ + compose(other) { + return this.chain(() => other) + } + step() { return this.#fn(this._value) } @@ -65,7 +73,7 @@ export class Suspend extends Algebra(Monad) { } /** @template T */ -export class Pure extends Algebra(Monad, Comonad) { +export class Pure extends Algebra(Monad) { _value /** @param {T} value */ @@ -95,7 +103,7 @@ export class Pure extends Algebra(Monad, Comonad) { * @returns {Pure} */ map(f) { - return this.chain(x => new Pure(f(x))) + return this.chain(x => pure(f(x))) } /** @@ -107,8 +115,12 @@ export class Pure extends Algebra(Monad, Comonad) { return this.map(f) } - extract() { - return this._value + /** + * @template T + * @param {InferredMorphism} other + */ + compose(other) { + return this.chain(() => pure(other)) } step() { diff --git a/src/algebra/list.js b/src/algebra/list.js index e23dd0a..4b8c83c 100644 --- a/src/algebra/list.js +++ b/src/algebra/list.js @@ -1,7 +1,7 @@ import { concat } from '../iter.js' import { liftF } from './fn.js' import { Pure, Suspend } from './free.js' -import { AlgebraWithBase, Comonad, Foldable } from './index.js' +import { AlgebraWithBase, Category, Comonad, Foldable, Monoid } from './index.js' /** @import { InferredMorphism } from './types.js' */ @@ -11,7 +11,15 @@ const Nil = Symbol('Nil') * @template T * @extends {Pure} */ -class ListPure extends AlgebraWithBase(Pure)(Foldable) { +class ListPure extends AlgebraWithBase(Pure)(Category, Foldable, Monoid) { + static empty() { + return List.empty() + } + + static id() { + return List.empty() + } + head() { return this._value } @@ -35,7 +43,7 @@ class ListPure extends AlgebraWithBase(Pure)(Foldable) { * @template T * @extends {Suspend} */ -class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Comonad) { +class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Monoid, Comonad) { /** * @param {Iterator} iter */ @@ -79,6 +87,10 @@ class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Comonad) { extract() { return this.reduce(reduceArray, []) } + + static empty() { + return List.empty() + } } /** @@ -120,9 +132,3 @@ const Empty = new ListPure(Nil) */ const reduceArray = (acc, value) => acc.concat(value) - -const a = Array.from({ length: 10 }).map((_, i) => i) - -const wawa = List.from(a) -console.log(wawa.reduce((acc, value) => acc.concat(value), [])) - diff --git a/src/algebra/option.js b/src/algebra/option.js index 96158a5..42d729b 100644 --- a/src/algebra/option.js +++ b/src/algebra/option.js @@ -1,9 +1,9 @@ -import { Algebra, Foldable, Functor, Monad } from './index.js' +import { Algebra, Foldable, Monad, Monoid } from './index.js' /** @import { Morphism } from './types.js' */ /** @template T */ -export class Some extends Algebra(Monad, Foldable) { +export class Some extends Algebra(Monoid, Monad, Foldable) { /** @type {T} */ #value @@ -59,10 +59,14 @@ export class Some extends Algebra(Monad, Foldable) { reduce(f, init) { return f(init, this.#value) } + + empty() { + return Option.empty() + } } /** @template T */ -class None extends Algebra(Monad, Foldable) { +class None extends Algebra(Monoid, Monad, Foldable) { /** * @template R * @param {Morphism} _f @@ -99,6 +103,10 @@ class None extends Algebra(Monad, Foldable) { reduce(_f, init) { return init } + + empty() { + return Option.empty() + } } /** @@ -113,6 +121,10 @@ export class Option { static of(value) { return Some.of(value) } + + static empty() { + return none + } } /** diff --git a/src/algebra/reader.js b/src/algebra/reader.js new file mode 100644 index 0000000..16448b8 --- /dev/null +++ b/src/algebra/reader.js @@ -0,0 +1,71 @@ +import { id } from './fn.js' +import { Algebra, Monad } from './index.js' + +/** @import { InferredMorphism } from './types.js' */ + +/** + * @template T + * @typedef {InferredMorphism} ReaderFn + */ + +/** @template T */ +export class Reader extends Algebra(Monad) { + #run + + /** + * @param {InferredMorphism} run + */ + constructor(run) { + super() + + this.#run = run + } + + /** + * @template T + * @param {T} a + * @returns {Reader} + */ + static of(a) { + return new Reader(/** @type {InferredMorphism} */(_env => a)) + } + + /** @template T */ + static ask() { + return new Reader(/** @type {InferredMorphism} */(id)) + } + + /** + * @param {InferredMorphism} f + * @returns {Reader} + */ + map(f) { + return new Reader(/** @type {InferredMorphism} */(env => f(this.#run(env)))) + } + + /** + * @param {InferredMorphism} f + * @returns {Reader} + */ + chain(f) { + return new Reader(env => f(this.#run(env)).run(env)) + } + + /** + * @param {InferredMorphism} f + * @returns {Reader} + */ + local(f) { + return new Reader(/** @type {InferredMorphism} */(env => this.#run(f(env)))) + } + + /** + * @template R + * @param {T} env + * @returns {R} + */ + run(env) { + return this.#run(env) + } +} + diff --git a/src/algebra/result.js b/src/algebra/result.js index 833be79..14a4f6c 100644 --- a/src/algebra/result.js +++ b/src/algebra/result.js @@ -15,6 +15,7 @@ export class Ok extends Algebra(Monad, Foldable) { */ constructor(value) { super() + this.#value = value }