Skip to content

Instantly share code, notes, and snippets.

@awto
Last active March 9, 2019 14:38
Show Gist options
  • Save awto/487bbcc847a6ce5e76ca088b6a95e749 to your computer and use it in GitHub Desktop.
Save awto/487bbcc847a6ce5e76ca088b6a95e749 to your computer and use it in GitHub Desktop.
Abstract Suspense
/** effectful expression throws this object if it requires suspension */
const token = {};
/** Pointer to mutable data used to record effectful computations */
let context;
/** Runs `thunk()` as an effectful expression with `of` and `chain` as Monad's definition */
const run = (of, chain) => thunk => {
/** here it caches effects requests */
const trace = [];
const ctx = {trace};
return step();
function step() {
const savedContext = context;
ctx.pos = 0;
try {
context = ctx;
return of(thunk());
} catch(e) {
/** re-throwing other exceptions */
if (e !== token)
throw e;
const {pos} = ctx;
return chain(ctx.effect,
(value) => {
trace.length = pos;
/* recording the resolved value */
trace[pos] = value;
ctx.pos = pos + 1;
/** replay */
return step(value);
})
} finally {
context = savedContext;
}
}
}
/** marks effectful expression */
const M = eff => {
/* if the execution is in a replay stage the value will be cached */
if (context.pos < context.trace.length)
return context.trace[context.pos++];
/* saving the expression to resolve in `run` */
context.effect = eff;
throw token;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment