122 lines
2 KiB
JavaScript
122 lines
2 KiB
JavaScript
import { chain, constant, Self, Value } from './common.js'
|
|
|
|
/** @import { Applicative, Morphism, Set } from './common.js' */
|
|
|
|
/**
|
|
* @template T
|
|
* @typedef {Some<T> | 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<T> & Set<T> & SomeMethods<T>} 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<T>}
|
|
* @param {Morphism<T, U>} fn
|
|
* @returns {Option<U>}
|
|
*/
|
|
function map(fn) {
|
|
return this[Self](this.chain(fn))
|
|
}
|
|
|
|
/**
|
|
* @template T, U
|
|
* @this {Option<T>}
|
|
* @param {Morphism<T, U>} 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<T>}
|
|
* @param {Option<T>} other
|
|
* @returns {Option<T>}
|
|
*/
|
|
function alt(other) {
|
|
return this.isSome() ? this : other
|
|
}
|
|
|
|
/**
|
|
* @template T
|
|
* @this {Option<T>}
|
|
* @returns {this is Some<T>}
|
|
*/
|
|
function isSome() {
|
|
return this[Self] === Some
|
|
}
|
|
|
|
/**
|
|
* @template T
|
|
* @this {Option<T>}
|
|
* @returns {this is None}
|
|
*/
|
|
function isNone() {
|
|
return this === None
|
|
}
|
|
|
|
/**
|
|
* @template T
|
|
* @param {?T} value
|
|
* @returns {Some<T>}
|
|
*/
|
|
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<T>}
|
|
*/
|
|
export const Option = value => Some(value)
|
|
Option.of = Option
|
|
Option.zero = None
|
|
|