JSFiddle - React, Tailwind, and code Playground
by dp0ch
JavaScript
const MAYBE = Symbol('MAYBE');
const Nothing = Object.freeze({
bind: () => Nothing,
toString: () => 'Nothing',
isSome: false,
isNone: true,
get value() {throw new Error('Tried to access value on Nothing')},
or: (v) => Just(v),
[MAYBE]: true,
});
function Just (a) {
if (a && a[MAYBE]) return a;
const monad = Object.freeze({
bind: (f) => Maybe(f(a)),
toString: () => `Just(${a})`,
isSome: true,
isNone: false,
get value() {return a},
or: () => monad,
[MAYBE]: true,
});
return monad;
}
function Maybe(v) {
return (
v === undefined ||
v === null ||
(typeof v === "number" && isNaN(v))
) ? Nothing : Just(v);
}
Maybe.do = (generator) => (...args) => {
const iterator = generator(...args);
function iterBind(v) {
const {value, done} = iterator.next(v);
if(done) return Maybe(value);
return Maybe(value).bind(iterBind);
}
return Just().bind(iterBind);
}
Maybe.all = (maybes) => maybes
.map(Maybe)
.reduce((acc, maybe) => acc.bind((vals) => maybe.bind((val) => [...vals, val])), Just([]));
function op() {
return Math.random() < 0.5 ? Nothing : Just(Math.floor(Math.random() * 10));
}
function NaN50() {
return Math.random() < 0.5 ? NaN : 1;
}
//TEST
const maybeAdd = () => Maybe.all([op(), op(), op()])
.bind(([a, b, c]) => a + b + c);
const maybeAddDo = Maybe.do(function* () {
const a = yield op();
const b = yield op();
const c = yield op();
return a + b + c;
});
console.log(maybeAdd().or(null).value);
console.log(maybeAddDo().or(null).value);