UNPKG

spica

Version:

Supervisor, Coroutine, Channel, select, AtomicPromise, Cancellation, Cache, List, Queue, Stack, and some utils.

134 lines (127 loc) 5.13 kB
import { AtomicPromise } from './promise'; import { curry } from './curry'; import { push } from './array'; export interface Maybe<a> { fmap<b>(f: (a: a) => b): Maybe<b>; ap<a, z>(this: Maybe<(a: a) => z>, a: Maybe<a>): Maybe<z>; ap<a, b, z>(this: Maybe<(a: a, b: b) => z>, a: Maybe<a>): Maybe<(b: b) => z>; ap<a, b, c, z>(this: Maybe<(a: a, b: b, c: c) => z>, a: Maybe<a>): Maybe<(b: b, c: c) => z>; ap<a, b, c, d, z>(this: Maybe<(a: a, b: b, c: c, d: d) => z>, a: Maybe<a>): Maybe<(b: b, c: c, d: d) => z>; ap<a, b, c, d, e, z>(this: Maybe<(a: a, b: b, c: c, d: d, e: e) => z>, a: Maybe<a>): Maybe<(b: b, c: c, d: d, e: e) => z>; bind<b>(f: (a: a) => Maybe<b>): Maybe<b>; join<b>(this: Maybe<Maybe<b>>): Maybe<b>; guard(cond: boolean): Maybe<a>; extract(): a; extract(nothing: () => a): a; extract<b>(nothing: () => b): a | b; extract<b>(nothing: () => b, just: (a: a) => b): b; } class Just<a> implements Maybe<a> { constructor( private readonly value: a, ) { } public fmap<b>(f: (a: a) => b): Just<b> { return new Just(f(this.value)); } public ap<a, z>(this: Maybe<(a: a) => z>, a: Maybe<a>): Maybe<z>; public ap<a, b, z>(this: Maybe<(a: a, b: b) => z>, a: Maybe<a>): Maybe<(b: b) => z>; public ap<a, b, c, z>(this: Maybe<(a: a, b: b, c: c) => z>, a: Maybe<a>): Maybe<(b: b, c: c) => z>; public ap<a, b, c, d, z>(this: Maybe<(a: a, b: b, c: c, d: d) => z>, a: Maybe<a>): Maybe<(b: b, c: c, d: d) => z>; public ap<a, b, c, d, e, z>(this: Maybe<(a: a, b: b, c: c, d: d, e: e) => z>, a: Maybe<a>): Maybe<(b: b, c: c, d: d, e: e) => z>; public ap<a, z>(this: Maybe<(...as: any[]) => z>, a: Maybe<a>): Maybe<z> { return Maybe.ap(this, a); } public bind<b>(f: (a: a) => Just<b>): Just<b>; public bind<b>(f: (a: a) => Nothing): Nothing; public bind<b>(f: (a: a) => Maybe<b>): Maybe<b>; public bind<b>(f: (a: a) => Maybe<b>): Maybe<b> { return f(this.value); } public join<b>(this: Just<Maybe<b>>): Maybe<b> { return this.value; } public guard(cond: boolean): Maybe<a> { return cond ? this : Maybe.mzero; } public extract(): a; public extract(nothing: () => a): a; public extract<b>(nothing: () => b): a | b; public extract<b>(nothing: () => b, just: (a: a) => b): b; public extract<b>(nothing?: () => b, just?: (a: a) => b): a | b { if (just !== undefined) return just(this.value); return this.value; assert(nothing); } } class Nothing implements Maybe<never> { public fmap<b>(f: (a: never) => b): Nothing { return this; assert(f); } public ap<a, z>(this: Maybe<(a: a) => z>, a: Maybe<a>): Nothing; public ap<a, b, z>(this: Maybe<(a: a, b: b) => z>, a: Maybe<a>): Nothing; public ap<a, b, c, z>(this: Maybe<(a: a, b: b, c: c) => z>, a: Maybe<a>): Nothing; public ap<a, b, c, d, z>(this: Maybe<(a: a, b: b, c: c, d: d) => z>, a: Maybe<a>): Nothing; public ap<a, b, c, d, e, z>(this: Maybe<(a: a, b: b, c: c, d: d, e: e) => z>, a: Maybe<a>): Nothing; public ap<a, z>(this: Maybe<(...as: any[]) => z>, _: Maybe<a>): Nothing { return this as Nothing; } public bind<b>(f: (a: never) => Maybe<b>): Nothing { return this; assert(f); } public join<b>(this: Maybe<Maybe<b>>): Nothing { return this as Nothing; } public guard(cond: boolean): Nothing { return this; assert(cond); } public extract(): never; public extract<b>(nothing: () => b): b; public extract<b>(nothing: () => b, just: (a: never) => b): b; public extract<b>(nothing?: () => b): b { if (nothing !== undefined) return nothing(); throw new Error(`Spica: Maybe: Nothing value is extracted`); assert(just); } } type just<a> = Just<a>; function just<a>(value: a): Just<a> { return new Just(value); } type nothing = Nothing; const nothing = new Nothing(); export { just as Just, nothing as Nothing, }; export namespace Maybe { export function fmap<a, b>(f: (a: a) => b, m: Maybe<a>): Maybe<b> { return m.fmap(f); } export const pure = just; export function ap<a, b>(mf: Maybe<(a: a) => b>, ma: Maybe<a>): Maybe<b>; export function ap<a, b>(mf: Maybe<(a: a) => b>): (ma: Maybe<a>) => Maybe<b>; export function ap<a, b>(af: Maybe<(a: a) => b>, aa?: Maybe<a>): Maybe<b> | ((aa: Maybe<a>) => Maybe<b>) { return aa ? af.bind(f => aa.fmap(curry(f))) : (aa: Maybe<a>) => ap(af, aa); } export const Return = pure; export function bind<a, b>(f: (a: a) => Maybe<b>, m: Maybe<a>): Maybe<b> { return m.bind(f); } export function sequence<a>(fm: Maybe<a>[]): Maybe<a[]>; export function sequence<a>(fm: Maybe<PromiseLike<a>>): AtomicPromise<Maybe<a>>; export function sequence<a>(fm: Maybe<a>[] | Maybe<PromiseLike<a>>): Maybe<a[]> | AtomicPromise<Maybe<a>> { return Array.isArray(fm) ? fm.reduce((acc, m) => acc.bind(as => m.fmap(a => push(as, [a]))), Return([])) : fm.extract(() => AtomicPromise.resolve(mzero), a => AtomicPromise.resolve(a).then(Return)); } export const mzero = nothing; export function mplus<a>(ml: Maybe<a>, mr: Maybe<a>): Maybe<a> { return ml.extract(() => mr, () => ml); } }