Skip to content

Instantly share code, notes, and snippets.

@Nymphium
Created July 22, 2019 00:30
Show Gist options
  • Select an option

  • Save Nymphium/47a168ece64ec69a6829d469769dc890 to your computer and use it in GitHub Desktop.

Select an option

Save Nymphium/47a168ece64ec69a6829d469769dc890 to your computer and use it in GitHub Desktop.
algebraic effects using stricter generator (is too hard or impossible).
interface Get {
readonly _tag: 'Get';
readonly _ans: number;
}
interface Put {
readonly _tag: 'Put';
readonly _ans: void;
value: number;
}
interface Log {
readonly _tag: 'Log';
readonly _ans: void;
value: string;
}
type Effects = Get | Put | Log;
type Answers = ({ [A in keyof Effects]: Effects[A] })['_ans'];
const genEff = <E, A>(obj: { [A in keyof E]: E[A] }) => ({
...obj,
_ans: (undefined as any) as A,
});
const get: Get = genEff({ _tag: 'Get' });
const put = (value: number): Put => genEff({ _tag: 'Put', value });
const log = (value: string): Log => genEff({ _tag: 'Log', value });
function run<R>(init: number, th: () => Iterator<Effects, R, Answers>) {
const iter = th();
let val = init;
function go(res: IteratorResult<Effects, R>): R {
if (res.done) {
return res.value;
}
const v = res.value;
switch (v._tag) {
case 'Get':
return go(iter.next(val));
case 'Put':
val = v.value;
return go(iter.next());
case 'Log':
console.log(`>>>${v.value}<<<`);
return go(iter.next());
}
}
return go(iter.next());
}
run(0, function*() {
// TS inferres return values from `yield` as anything `any`,
// or when explicitly typing this generator as `Iterator<Effects, void, Answers>`, always `number | void`
const x: number = yield get;
yield log(x.toString());
yield put(x + 10);
const y: number = yield get;
yield log(y.toString());
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment