kojima/src/algebra/result.js
2025-03-31 05:10:46 -05:00

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)