Created
June 16, 2019 05:33
-
-
Save bradparker/cb747056241917da6f72ccc9fcbad507 to your computer and use it in GitHub Desktop.
Geneator function do notation experiment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as Either from "./Either"; | |
type Action<I, E, A> = (input: I) => Promise<Either.Either<E, A>>; | |
export class App<I, E, A> { | |
public run: Action<I, E, A>; | |
public constructor(action: Action<I, E, A>) { | |
this.run = action; | |
} | |
public map<B>(f: (a: A) => B): App<I, E, B> { | |
return new App(input => { | |
return this.run(input).then(result => result.map(f)); | |
}); | |
} | |
public chain<B>(f: (a: A) => App<I, E, B>): App<I, E, B> { | |
return new App(input => { | |
return this.run(input).then(result => { | |
return result.run( | |
l => { | |
return Promise.resolve(new Either.Left(l)); | |
}, | |
r => { | |
return f(r).run(input); | |
} | |
); | |
}); | |
}); | |
} | |
public handleError<B>(f: (e: E) => App<I, E, A>): App<I, E, A> { | |
return new App(input => { | |
return this.run(input).then(result => { | |
return result.run( | |
l => { | |
return f(l).run(input); | |
}, | |
r => { | |
return Promise.resolve(new Either.Right(r)); | |
} | |
); | |
}); | |
}); | |
} | |
} | |
export const throwError = <I, E, A>(e: E): App<I, E, A> => | |
new App(() => Promise.resolve(new Either.Left(e))); | |
export const pure = <I, E, A>(a: A): App<I, E, A> => | |
new App(() => Promise.resolve(Either.pure(a))); | |
export const ask = <I, E, A>(): App<I, E, I> => | |
new App(input => Promise.resolve(Either.pure(input))); | |
export const appBlock = <I, E, A>( | |
block: () => Iterator<App<I, E, A>> | |
): App<I, E, A> => { | |
const iterator = block(); | |
const step = (value?: A) => { | |
const result = iterator.next(value); | |
if (result.done) { | |
return result.value; | |
} | |
return result.value.chain(step); | |
}; | |
return step(); | |
}; | |
const example1 = () => | |
appBlock(function*() { | |
const i = yield ask(); | |
const a = yield pure(1); | |
const b = yield pure("Foo"); | |
const c = yield throwError("This is no good").handleError(pure); | |
return pure(`${i} ${a.toString()} ${b} ${c.toString()}`); | |
}); | |
example1() | |
.run("Our env") | |
.then(console.log); | |
const example2 = () => | |
appBlock(function*() { | |
const a = yield example1(); | |
return pure(a); | |
}); | |
example2() | |
.run("I have no idea what this'll do") | |
.then(console.log); | |
ask() | |
.chain(input => pure(`We recieved: ${input}`)) | |
.run("Another example") | |
.then(console.log); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type Either<E, A> = Left<E, A> | Right<E, A>; | |
export class Left<E, A> { | |
public readonly tag: "Left" = "Left"; | |
public readonly value: E; | |
public constructor(value: E) { | |
this.value = value; | |
} | |
public map<B>(_f: (a: A) => B): Either<E, B> { | |
return new Left(this.value); | |
} | |
public chain<B>(_f: (a: A) => Either<E, B>): Either<E, B> { | |
return new Left(this.value); | |
} | |
public run<R>(l: (e: E) => R, _r: (a: A) => R): R { | |
return l(this.value); | |
} | |
} | |
export class Right<E, A> { | |
public readonly tag: "Right" = "Right"; | |
public readonly value: A; | |
public constructor(value: A) { | |
this.value = value; | |
} | |
public map<B>(f: (a: A) => B): Either<E, B> { | |
return new Right(f(this.value)); | |
} | |
public chain<B>(f: (a: A) => Either<E, B>): Either<E, B> { | |
return f(this.value); | |
} | |
public run<R>(l: (e: E) => R, r: (a: A) => R): R { | |
return r(this.value); | |
} | |
} | |
export const pure = <E, A>(a: A): Either<E, A> => { | |
return new Right(a); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment