122 lines
2 KiB
JavaScript
122 lines
2 KiB
JavaScript
import { chain, constant, Self, Value } from './common.js'
|
|
|
|
/** @import { Morphism } from './common.js' */
|
|
|
|
/**
|
|
* @template T, E
|
|
* @typedef {Ok<T> | Err<E>} Result
|
|
*/
|
|
|
|
/**
|
|
* @template T
|
|
* @typedef Ok
|
|
* @property {typeof isOk} isOk
|
|
* @property {typeof isErr} isErr
|
|
* @property {typeof chain} chain
|
|
* @property {typeof map} map
|
|
* @property {typeof alt} alt
|
|
* @property {typeof fold} fold
|
|
*/
|
|
|
|
/**
|
|
* @template T
|
|
* @typedef Err
|
|
* @property {typeof isOk} isOk
|
|
* @property {typeof isErr} isErr
|
|
* @property {typeof chain} chain
|
|
* @property {typeof map} map
|
|
* @property {typeof alt} alt
|
|
* @property {typeof fold} fold
|
|
*/
|
|
|
|
/**
|
|
* @template T, U, E
|
|
* @this {Result<T, E>}
|
|
* @param {Morphism<T, U>} fn
|
|
* @returns {Result<U, E>}
|
|
*/
|
|
function map(fn) {
|
|
return this[Self](this.chain(fn))
|
|
}
|
|
|
|
/**
|
|
* @template T, U, E
|
|
* @this {Result<T, E>}
|
|
* @param {Morphism<T, Result<U, E>>} fn
|
|
* @param {U} acc
|
|
* @return {U}
|
|
*/
|
|
function fold(fn, acc) {
|
|
const result = this.map(fn)
|
|
return result.isOk() ? result[Value] : acc
|
|
}
|
|
|
|
/**
|
|
* @template T, E
|
|
* @this {Result<T, E>}
|
|
* @param {Result<T, E>} other
|
|
* @returns {Result<T, E>}
|
|
*/
|
|
function alt(other) {
|
|
return this.isOk() ? this : other
|
|
}
|
|
|
|
/**
|
|
* @template T, E
|
|
* @this {Result<T, E>}
|
|
* @returns {this is Ok<T>}
|
|
*/
|
|
function isOk() {
|
|
return this[Self] === Ok
|
|
}
|
|
|
|
/**
|
|
* @template T, E
|
|
* @this {Result<T, E>}
|
|
* @returns {this is Err<E>}
|
|
*/
|
|
function isErr() {
|
|
return this[Self] === Err
|
|
}
|
|
|
|
/**
|
|
* @template T
|
|
* @param {?T} value
|
|
* @returns {Ok<T>}
|
|
*/
|
|
export const Ok = value => Object.freeze({
|
|
[Self]: Ok,
|
|
[Value]: value,
|
|
isOk,
|
|
isErr,
|
|
chain,
|
|
map,
|
|
alt,
|
|
fold
|
|
})
|
|
|
|
/**
|
|
* @template T
|
|
* @param {T?} value
|
|
* @returns {Err<T>}
|
|
*/
|
|
export const Err = value => Object.freeze({
|
|
[Self]: Err,
|
|
[Value]: value,
|
|
chain: constant,
|
|
map: constant,
|
|
alt,
|
|
isOk,
|
|
isErr,
|
|
fold
|
|
})
|
|
|
|
/**
|
|
* @template T, E
|
|
* @param {T} value
|
|
* @returns {Result<T, E>}
|
|
*/
|
|
export const Result = value => Ok(value)
|
|
Result.of = Result
|
|
Result.zero = () => Err(undefined)
|
|
|