class Functor {
constructor(val) {
this.val = val;
}
map(fn) {
return new this.constructor(fn(this.val));
}
}
class Pointed extends Functor {
static of(val) {
return new this.constructor(val);
}
}
class Either extends Pointed {
constructor(left, right) {
super(null);
this.left = left;
this.right = right;
}
static of(left, right) {
return new this.constructor(left, right);
}
is_nothing() {
return this.right === null || this.right === undefined;
}
map(fn) {
return this.is_nothing() ?
this.constructor.of(fn(this.left), this.right) :
this.constructor.of(this.left, fn(this.right));
}
}
class Applicative extends Pointed {
apply(fo) {
return fo.map(this.val);
}
}
class Monad extends Pointed {
static of(val) {
return new this.constructor(val);
}
join() {
if (this.val instanceof this.constructor) {
this.val = this.val.val
this.join()
}
return this;
}
flatmap(fn) {
return this.map(fn).join();
}
}
class Maybe extends Monad {
is_nothing() {
return this.val == null || this.val == undefined;
}
map(fn) {
return this.is_nothing() ?
this.constructor.of(null) :
this.constructor.of(fn(this.val));
}
}