Skip to content

Instantly share code, notes, and snippets.

@gerardpaapu
Last active December 24, 2017 11:38
Show Gist options
  • Save gerardpaapu/9283992 to your computer and use it in GitHub Desktop.
Save gerardpaapu/9283992 to your computer and use it in GitHub Desktop.
A lazy Either monad for TypeScript
export interface Monad<T> {
chain<TT>(f: (v: T) => Monad<TT>): Monad<TT>;
concat(m: Monad<T>): Monad<T>;
empty<T>(): Monad<T>;
map<A, B>(f: (A: any) => B): Monad<B>;
of<A>(v: A): Monad<A>;
}
export declare class Either<T, E> implements Monad<T> {
private doFork;
constructor(doFork: (f: (value: T) => Object, g: (error: E) => Object) => Object);
static fail<A, F>(error: F): Either<A, F>;
static of<A, F>(value: A): Either<A, F>;
static empty<A, F>(): Either<A, F>;
public fork<A>(f: (value: T) => A, g: (error: E) => A): A;
public of<A, F>(value: A): Either<A, F>;
public fail<A, F>(error: F): Either<A, F>;
public empty(): Either<T, E>;
public getValue(): T;
public chain<TT>(m: (value: T) => Either<TT, E>): Either<TT, E>;
public map<A>(m: (value: T) => A): Either<A, E>;
public concat(either: Either<T, E>): Either<T, E>;
}
export declare class Promise<V, E> implements Monad<V> {
private doTap;
constructor(doTap: (cb: (e: Either<V, E>) => void) => void);
static of<VV, EE>(v: VV): Promise<VV, EE>;
static fail<VV, EE>(e: EE): Promise<VV, EE>;
static empty<VV, EE>(): Promise<VV, EE>;
public of<VV, EE>(v: VV): Promise<VV, EE>;
public empty<VV, EE>(): Promise<VV, EE>;
public fail<VV, EE>(e: EE): Promise<VV, EE>;
public tap(cb: (e: Either<V, E>) => void): void;
public map<VV>(f: (_: V) => VV): Promise<VV, E>;
public chain<VV>(f: (_: V) => Promise<VV, E>): Promise<VV, E>;
public concat(other: Promise<V, E>): Promise<V, E>;
}
define(["require", "exports"], function(require, exports) {
var Either = (function () {
function Either(doFork) {
this.doFork = doFork;
}
Either.fail = function (error) {
return new Either(function (f, g) {
return g(error);
});
};
Either.of = function (value) {
return new Either(function (f, g) {
return f(value);
});
};
Either.empty = function () {
return this.fail(null);
};
Either.prototype.fork = function (f, g) {
return this.doFork.call(null, f, g);
};
Either.prototype.of = function (value) {
return Either.of(value);
};
Either.prototype.fail = function (error) {
return Either.fail(error);
};
Either.prototype.empty = function () {
return Either.empty();
};
Either.prototype.getValue = function () {
return this.fork((function (v) {
return v;
}), (function (e) {
throw e;
}));
};
Either.prototype.chain = function (m) {
var _this = this;
return new Either(function (f, g) {
return _this.fork((function (v) {
return m(v).fork(f, g);
}), g);
});
};
Either.prototype.map = function (m) {
var _this = this;
return this.chain(function (v) {
return _this.of(m(v));
});
};
Either.prototype.concat = function (either) {
var _this = this;
return new Either(function (f, g) {
return _this.fork(f, function (err) {
return either.fork(f, g);
});
});
};
return Either;
})();
exports.Either = Either;
;
var Promise = (function () {
function Promise(doTap) {
this.doTap = doTap;
}
Promise.of = function (v) {
return new Promise(function (cb) {
cb(Either.of(v));
});
};
Promise.fail = function (e) {
return new Promise(function (cb) {
cb(Either.fail(e));
});
};
Promise.empty = function () {
return Promise.fail(null);
};
Promise.prototype.of = function (v) {
return Promise.of(v);
};
Promise.prototype.empty = function () {
return Promise.empty();
};
Promise.prototype.fail = function (e) {
return Promise.fail(e);
};
Promise.prototype.tap = function (cb) {
window.setImmediate(function () {
this.doTap(cb);
});
};
Promise.prototype.map = function (f) {
return this.chain(function (v) {
return Promise.of(f(v));
});
};
Promise.prototype.chain = function (f) {
var _this = this;
return new Promise(function (cb) {
return _this.tap(function (either) {
either.fork(function (v) {
f(v).tap(cb);
}, function (e) {
cb(Either.fail(e));
});
});
});
};
Promise.prototype.concat = function (other) {
var _this = this;
return new Promise(function (cb) {
return _this.tap(function (either) {
either.fork(function (v) {
cb(Either.of(v));
}, function (_) {
other.tap(cb);
});
});
});
};
return Promise;
})();
exports.Promise = Promise;
function filterM(m, f) {
return m.chain(function (v) {
return (f(v)) ? m.of(v) : m.empty();
});
}
});
export interface Monad<T> {
chain<TT>(f : (v: T) => Monad<TT>) : Monad<TT>;
concat (m:Monad<T>) : Monad<T>;
empty<T>() : Monad<T>;
map<A, B>(f:(A) => B) : Monad<B>;
of<A>(v:A): Monad<A>;
}
export class Either<T, E> implements Monad<T> {
constructor (private doFork: (f: (value: T) => Object,
g: (error: E) => Object) => Object) {
}
static fail<A, F> (error: F) : Either<A, F> {
return new Either<A, F>((f, g) => g(error));
}
static of<A, F> (value: A) : Either<A, F> {
return new Either<A, F>((f, g) => f(value));
}
static empty<A, F> () : Either<A, F> {
return this.fail<A, F>(null);
}
fork<A> (f: (value: T) => A, g: (error: E) => A) : A {
return <A>this.doFork.call(null, f, g);
}
of<A, F> (value: A) : Either<A, F> {
return Either.of<A, F>(value);
}
fail<A, F> (error: F) : Either<A, F> {
return Either.fail<A, F>(error);
}
empty (): Either <T, E> {
return Either.empty<T, E>();
}
getValue () : T {
return this.fork<T>(
((v) => v),
((e):T => {
throw e;
}));
}
chain<TT>(m: (value:T) => Either<TT, E>) : Either<TT, E> {
return new Either<TT, E>((f, g) => this.fork(
((v) => m(v).fork(f, g)),
g
));
}
map<A>(m: (value: T) => A) : Either<A, E> {
return this.chain<A>((v) => this.of<A, E>(m(v)));
}
concat(either: Either<T, E>) : Either<T, E> {
return new Either<T, E>(
(f, g) => this.fork(f, (err) => either.fork(f, g))
);
}
};
export class Promise<V,E> implements Monad<V> {
constructor (private doTap: (cb: (e:Either<V, E>) => void) => void) {}
static of<VV, EE>(v: VV) : Promise<VV, EE> {
return new Promise<VV,EE>(function (cb) {
cb(Either.of<VV, EE>(v))
});
}
static fail<VV, EE>(e: EE) : Promise<VV, EE> {
return new Promise<VV, EE>(function (cb) {
cb(Either.fail<VV, EE>(e));
});
}
static empty<VV, EE> () : Promise<VV, EE> {
return Promise.fail<VV, EE>(null);
}
of<VV, EE>(v: VV) : Promise<VV, EE> {
return Promise.of<VV, EE>(v);
}
empty<VV, EE>() : Promise<VV, EE> {
return Promise.empty<VV, EE>();
}
fail<VV, EE>(e:EE) : Promise<VV, EE> {
return Promise.fail<VV, EE>(e);
}
tap (cb:(e:Either<V,E>) => void):void {
window.setImmediate(function () { this.doTap(cb) });
}
map<VV> (f:(_:V) => VV): Promise<VV, E> {
return this.chain((v) => Promise.of<VV, E>(f(v)));
}
chain<VV> (f:(_:V) => Promise<VV, E>) {
return new Promise<VV, E>((cb) => this.tap(function (either:Either<V, E>):void {
either.fork(
function (v) { f(v).tap(cb) },
function (e) { cb(Either.fail<VV, E>(e)) });
}));
}
concat (other: Promise<V, E>) {
return new Promise<V, E>((cb) => this.tap(function (either) {
either.fork(
function (v) { cb(Either.of<V, E>(v)) },
function (_) { other.tap(cb) });
}));
}
}
function filterM<A>(m:Monad<A>, f:(v:A) => boolean):Monad<A> {
return m.chain((v) => (f(v)) ? m.of(v) : m.empty());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment