kojima/src/algebra/option.js

145 lines
2.1 KiB
JavaScript

import { Algebra, Foldable, Monad, Monoid, Setoid } from './interfaces.js'
/** @import { Morphism } from './types.js' */
/** @template T */
export class Some extends Algebra(Setoid, Monoid, Monad, Foldable) {
/** @type {T} */
#value
/** @param {T} value */
constructor(value) {
super()
this.#value = value
}
/**
* @template T
* @param {T} value
* @returns {Some<T>}
*/
static of(value) {
return new Some(value)
}
equals(other) {
return other instanceof Some &&
other.chain(v => v === this.#value)
}
/**
* @template R
* @param {Morphism<T, R>} f
* @returns {R}
*/
chain(f) {
return f(this.#value)
}
/**
* @template R
* @param {Morphism<T, R>} f
* @returns {Some<R>}
*/
map(f) {
return Some.of(this.chain(f))
}
/**
* @template R
* @param {Morphism<T, R>} f
* @returns {Some<R>}
*/
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)
}
empty() {
return Option.empty()
}
}
/** @template T */
export class None extends Algebra(Setoid, Monoid, Monad, Foldable) {
equals(other) {
return other === none
}
/**
* @template R
* @param {Morphism<T, R>} _f
* @returns {None}
*/
chain(_f) {
return this
}
/**
* @template R
* @param {Morphism<T, R>} _f
* @returns {None}
*/
map(_f) {
return this
}
/**
* @template R
* @param {Morphism<T, R>} _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
}
empty() {
return Option.empty()
}
}
/**
* @template T
* @type {Some<T> | None<T>} Option
*/
export class Option {
/**
* @template T
* @param {T} value
*/
static of(value) {
return Some.of(value)
}
static empty() {
return none
}
}
/**
* @template T
* @param {T} value
*/
export const some = value => new Some(value)
export const none = new None()