import { Algebra, Foldable, Monad, Setoid } from './interfaces.js' /** @import { Morphism } from './types.js' */ const Interfaces = Algebra(Setoid, Monad, Foldable) /** * @template T * @typedef {Some | None} Option */ /** @template T */ export class Some extends Interfaces { /** @type {T} */ #value /** @param {T} value */ constructor(value) { super() this.#value = value } /** * @param {Option} other */ equals(other) { return other instanceof Some && other.chain(v => v === this.#value) } ap(b) { return b.chain(f => this.map(f)) } /** * @template R * @param {Morphism} f * @returns {R} */ chain(f) { return f(this.#value) } /** * @template R * @param {Morphism} f * @returns {Some} */ map(f) { return Some.of(this.chain(f)) } /** * @template R * @param {Morphism} f * @returns {Some} */ then(f) { return this.map(f) } /** * @template U * @param {(acc: U, value: T) => U} f * @param {U} init * @returns {U} */ reduce(f, init) { return f(init, this.#value) } } /** @template T */ export class None extends Interfaces { /** * @param {Option} other */ equals(other) { return other === none } ap(_b) { return this } /** * @template R * @param {Morphism} _f * @returns {None} */ chain(_f) { return this } /** * @template R * @param {Morphism} _f * @returns {None} */ map(_f) { return this } /** * @template R * @param {Morphism} _f * @returns {None} */ then(_f) { return this } /** * @template U * @param {(acc: U, value: T) => U} _f * @param {U} init * @returns {U} */ reduce(_f, init) { return init } } /** * @template T * @param {T} value */ 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