/** * wrapIO a value in the IO monad */ export const wrapIO = (a: A) => new IO(() => a); /** * safeIO accepts a function that has side effects and wrapIOs it in an IO Monad. */ export const safeIO = (f: () => A) => new IO(f); export const pure = wrapIO; export const suspend = safeIO; /** * IO monadic type for containing interactions with the 'real world'. */ export class IO { constructor(private effect: () => A) { } static safeIO = safeIO; static pure = pure; static suspend = suspend; static chain = (f: (a: A) => IO) => (m: IO): IO => m.chain(f); of(v: A): IO { return new IO(() => v); } map(f: (a: A) => B): IO { return new IO(() => f(this.effect())); } mapIn(b: B): IO { return this.map(() => b); } /** * chain */ chain(f: (a: A) => IO): IO { return new IO(() => f(this.effect()).run()); } chainIn(b: B): IO { return this.chain(() => wrapIO(b)); } /** * run */ run(): A { return this.effect(); } }