Last active
March 9, 2019 14:38
-
-
Save awto/487bbcc847a6ce5e76ca088b6a95e749 to your computer and use it in GitHub Desktop.
Abstract Suspense
This file contains hidden or 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
/** 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