pragmatic-fp-ts
Version:
Opinionated functional programming library with easy use in mind
112 lines (102 loc) • 2.79 kB
text/typescript
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);