Skip to content

Instantly share code, notes, and snippets.

@afcastano
Last active June 16, 2020 11:54
Show Gist options
  • Save afcastano/dd94b85bc65519eb55784ac1cec45839 to your computer and use it in GitHub Desktop.
Save afcastano/dd94b85bc65519eb55784ac1cec45839 to your computer and use it in GitHub Desktop.
Typescript IO monad with Promises
export class IO<A>{
private effect: Effect<A>
constructor(effect: Effect<A>) {
this.effect = effect
}
static of<T>(val: T) {
return new IO(() => Promise.resolve(val))
}
map<B>(f: (val: A) => B): IO<B> {
const mappedEffect: Effect<B> = async (effects: Effects) => {
const unwrappedVal: A = await this.effect(effects);
return f(unwrappedVal);
};
return new IO(mappedEffect);
}
flatMap<B>(f: (val: A) => IO<B>): IO<B> {
const boundEffect: Effect<B> = async (effects: Effects) => {
const unwrappedVal: A = await this.effect(effects);
const mappedIO: IO<B> = f(unwrappedVal);
return mappedIO.effect(effects);
}
return new IO(boundEffect);
}
eval(effects: Effects): Promise<A> {
return this.effect(effects)
}
}
export const _do = (fn: (...args: any[]) => Generator<IO<any>, any, any>) => (...args: any[]) => {
const gen = fn(...args);
const next = (val?: any) => {
const res: any = gen.next(val);
if(!res.done) return res.value.flatMap(next);
if(res.value && res.value.effect) return res.value;
return IO.of(res.value);
}
return next();
}
export type Effect<T> = (effects: Effects) => Promise<T>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment