import { chain, constant, Self, Value } from './common.js' /** @import { Applicative, Morphism, Set } from './common.js' */ /** * @template T * @typedef {Some | None} Option */ /** * @template T * @typedef SomeMethods * @property {typeof isSome} isSome * @property {typeof isNone} isNone * @property {typeof chain} chain * @property {typeof map} map * @property {typeof alt} alt * @property {typeof fold} fold */ /** * @template T * @typedef {Applicative & Set & SomeMethods} Some * @variation 1 */ /** * @typedef None * @property {typeof isSome} isSome * @property {typeof isNone} isNone * @property {typeof chain} chain * @property {typeof map} map * @property {typeof alt} alt * @property {typeof fold} fold */ /** * @template T, U * @this {Option} * @param {Morphism} fn * @returns {Option} */ function map(fn) { return this[Self](this.chain(fn)) } /** * @template T, U * @this {Option} * @param {Morphism} fn * @param {U} acc * @return {U} */ function fold(fn, acc) { const result = this.map(fn) return result.isSome() ? result[Value] : acc } /** * @template T * @this {Option} * @param {Option} other * @returns {Option} */ function alt(other) { return this.isSome() ? this : other } /** * @template T * @this {Option} * @returns {this is Some} */ function isSome() { return this[Self] === Some } /** * @template T * @this {Option} * @returns {this is None} */ function isNone() { return this === None } /** * @template T * @param {?T} value * @returns {Some} */ export const Some = value => ({ [Self]: Some, [Value]: value, isSome, isNone, chain, map, alt, fold }) /** * @returns {None} */ export const None = () => None None.isSome = isSome None.isNone = isNone None.chain = constant None.map = constant None.alt = alt None.fold = fold /** * @template T * @param {?T} value * @returns {Option} */ export const Option = value => Some(value) Option.of = Option Option.zero = None