Skip to content

Instantly share code, notes, and snippets.

@mdubourg001
Last active February 12, 2020 10:20
Show Gist options
  • Save mdubourg001/640c2ae1e34f2e3d81c71d662126373f to your computer and use it in GitHub Desktop.
Save mdubourg001/640c2ae1e34f2e3d81c71d662126373f to your computer and use it in GitHub Desktop.
TypeScript Maybe Monad Implementation
abstract class Monad<T> {
protected value: T;
}
class Maybe<T> extends Monad<T> {
constructor(val: T | null) {
super();
this.value = val;
}
static Just<T>(val: T): Maybe<T> {
return new Maybe(val);
}
static Nothing<T>(val?: T): Maybe<T> {
return new Maybe(null);
}
static of<T>(val: T): Maybe<T> {
return Maybe.Just(val);
}
map<B>(f: (val: T) => B): Maybe<T | B> {
return this.isNothing() ? this : new Maybe(f(this.value));
}
join(): T {
return this.value;
}
isNothing(): boolean {
return this.value === null;
}
equals(m: Maybe<T>): boolean {
return this.value === m.join();
}
toString(): string {
return this.isNothing() ? "Nothing" : `Just ${this.value}`;
}
}
// -----
// utils
// -----
const log = (...args: any[]) => console.log(`=> ${args.join(' ')}`);
/**
* calls and returns the result of either 'iftrue' or 'iffalse' functions
* based on the result of the pred function evalutation
*/
const cond = (
pred: (val: any) => boolean,
iftrue: (val: any) => any,
iffalse: (val: any) => any,
) => (val: any) => (pred(val) ? iftrue(val) : iffalse(val));
const isUndefined = (x: any) => x === undefined;
// -----
// examples
// -----
const { Just, Nothing } = Maybe;
let m = new Maybe(42);
log(m); // => Just 42
m = Just(42);
log(m); // => Just 42
m = Nothing(42);
log(m); // => Nothing
const double = (x: number) => x * 2;
m = Nothing(10)
.map(double)
.map(double);
log(m); // => Nothing
log(m.equals(Nothing())); // => true
m = Just(5)
.map(double)
.map(double);
log(m); // => Just 20
let b = Just(5)
.map(double)
.map(double)
.equals(m);
log(b); // => true
let n = Just(5)
.map(double)
.map(double)
.join();
log(n); // => 20
const getDataThatMayBeUndefined = (): Object | undefined => {
const r: number = Math.random();
switch (true) {
case r <= 0.5:
return {
firstname: 'John',
lastname: 'Doe',
age: 21,
};
case r > 0.5:
return undefined;
}
};
const doubleAge = (x: any) => ({ ...x, age: x.age * 2 });
const maybeDoubleAge = (x: any) => Maybe.of({ ...x, age: x.age * 2 });
const data = cond(isUndefined, Nothing, Just)(getDataThatMayBeUndefined());
log(data); // => Just [object Object] | Nothing
data
.map(doubleAge)
.flatMap(maybeDoubleAge)
.map(doubleAge)
.map((x: any) => log(x.age)); // => 168
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment