UNPKG

pragmatic-fp-ts

Version:

Opinionated functional programming library with easy use in mind

112 lines (102 loc) 2.79 kB
import { Effect, getValue, identity, Mappable, Predicate } from "./main.ts"; import { Monad } from "./types.ts"; export type Maybe<A> = Just<A> | Nothing<A>; export type MaybeMatcher<A, B> = { just?: Mappable<NonNullable<A>, B>; nothing?: () => B }; export class Nothing<A> extends Monad<A> { _<B>(_: Mappable<A, B>): Maybe<NonNullable<B>> { return this as any; } bind = this._; bindM<B>(_: Mappable<Monad<A>, Monad<B>>): Maybe<NonNullable<B>> { return this as any; } filter(_: any): Maybe<NonNullable<A>> { return this as any; } effect(_: any): Maybe<NonNullable<A>> { return this as any; } getValue(): A { throw new Error("Can not get value of Nothing"); } getValueOr(alt: A): A { return alt; } match<B>(matcher: MaybeMatcher<A, B>): Maybe<NonNullable<B>> { return matcher.nothing ? maybe(matcher.nothing()) : (this as any); } isNothing() { return true; } isJust() { return false; } } export class Just<A> extends Monad<A> { readonly value: A; constructor(value: A) { super(); this.value = value; } _<B>(fn: Mappable<A, B>): Maybe<NonNullable<B>> { try { const result = fn(this.value); return maybe(getValue(result)); } catch (err) { return nothing<never>(); } } bind = this._; bindM<B>(fn: Mappable<Monad<A>, Monad<B>>): Maybe<NonNullable<B>> { try { const result = fn(this); return maybe(getValue(result)); } catch (err) { return nothing<never>(); } } filter(fn: Predicate<A>): Maybe<NonNullable<A>> { try { return fn(this.value) ? (this as any) : nothing<never>(); } catch { return nothing<never>(); } } effect(fn: Effect<A>): Maybe<NonNullable<A>> { try { fn(this.value); } catch (err) {} return this as any; } getValue(): NonNullable<A> { return this.value as NonNullable<A>; } getValueOr(_: A): A { return this.value; } match<B>(matcher: MaybeMatcher<A, B>): Maybe<NonNullable<B>> { const m = matcher.just || (identity as any); return maybe(m(this.value as NonNullable<A>)); } isNothing() { return false; } isJust() { return true; } } export const just = <T>(value: T) => { return new Just<T>(value); }; export const nothing = <T>() => { return new Nothing<T>(); }; export const maybe = <U, T = NonNullable<U>>(value: U | Monad<U>): Maybe<T> => { const extractedValue = getValue<U>(value); return extractedValue === null || extractedValue === undefined ? (nothing() as Nothing<T>) : just<T>(extractedValue as any); }; export const isJust = (x: unknown) => x instanceof Just; export const isNothing = (x: unknown) => x instanceof Nothing; export const isMaybe = (x: unknown) => isJust(x) || isNothing(x);