import { Monad } from '../monad/Monad';
/**
* left wraps a value on the left side.
*/
export const left = (a: A) => new Left(a);
/**
* right wraps a value on the right side.
*/
export const right = (b: B) => new Right(b);
/**
* fromBoolean constructs an Either using a boolean value.
*/
export const fromBoolean = (b: boolean): Either =>
b ? right(true) : left(false);
/**
* Either monad implementation
*/
export abstract class Either implements Monad {
static left = left;
static right = right;
static fromBoolean = fromBoolean;
of(v: R): Either {
return new Right(v);
}
abstract map(f: (r: R) => B): Either;
abstract mapLeft(f: (l: L) => B): Either;
abstract bimap(f: (l: L) => LL, g: (r: R) => RR): Either;
/**
* chain
*/
abstract chain(f: (r: R) => Either): Either;
/**
* orElse returns the result of f if the Either is left.
*/
abstract orElse(f: (l: L) => Either): Either;
/**
* orRight is like orElse except it just expects the value
*/
abstract orRight(f: (l: L) => R): Either;
/**
* ap
*/
abstract ap(e: Either B>): Either;
/**
* takeLeft extracts the left value of an Either, throwing an error if the Either is right.
*/
abstract takeLeft(): L;
/**
* takeRight is the opposite of left
* @summary Either → B|Error
*/
abstract takeRight(): R;
/**
* cata
*/
abstract cata(f: (l: L) => B, g: (r: R) => B): B;
}
export class Left extends Either {
constructor(public l: L) { super(); }
map(_: (r: R) => B): Either {
return new Left(this.l);
}
mapLeft(f: (l: L) => B): Either {
return new Left(f(this.l));
}
bimap(f: (l: L) => LL, _: (r: R) => RR): Either {
return left(f(this.l));
}
chain(_: (r: R) => Either): Either {
return new Left(this.l);
}
orElse(f: (l: L) => Either): Either {
return f(this.l);
}
orRight(f: (l: L) => R): Either {
return new Right(f(this.l));
}
ap(_: Either B>): Either {
return new Left(this.l);
}
takeLeft(): L {
return this.l;
}
takeRight(): R {
throw new TypeError(`Not right!`);
}
cata(f: (l: L) => B, _: (r: R) => B): B {
return f(this.l);
}
}
export class Right extends Either {
constructor(public r: R) { super(); }
map(f: (r: R) => B): Either {
return new Right(f(this.r));
}
mapLeft(_: (l: L) => B): Either {
return new Right(this.r);
}
bimap(_: (l: L) => LL, g: (r: R) => RR): Either {
return right(g(this.r));
}
chain(f: (r: R) => Either): Either {
return f(this.r);
}
/**
* orElse returns the result of f if the Either is left.
*/
orElse(_: (l: L) => Either): Either {
return this;
}
orRight(_: (l: L) => R): Either {
return this;
}
/**
* ap
*/
ap(e: Either B>): Either {
return e.map(f => f(this.r));
}
/**
* takeLeft extracts the left value of an Either, throwing an error if the Either is right.
*/
takeLeft(): L {
throw new TypeError(`Not left!`);
}
takeRight(): R {
return this.r;
}
/**
* cata
*/
cata(_: (l: L) => B, g: (r: R) => B): B {
return g(this.r);
}
}