Skip to content

Instantly share code, notes, and snippets.

@yelouafi
Created September 21, 2018 17:05
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yelouafi/858095244b62c36ec7ebb84d5f3e5b02 to your computer and use it in GitHub Desktop.
Save yelouafi/858095244b62c36ec7ebb84d5f3e5b02 to your computer and use it in GitHub Desktop.
multi shot continuations
function isGenerator(x) {
return x != null && typeof x.next === "function"
}
function isFrame(x) {
return x != null && x._type_ === 'call_frame'
}
function call(genFunc, ...args) {
return { _type_: 'call_frame', genFunc, args, history: [] }
}
function runFrame(frame, arg, next) {
const {genFunc, args, history} = frame
// rebuilds the state of the Generator
const gen = genFunc(...args)
history.forEach(result => gen.next(result))
const {done, value} = gen.next(arg)
if(done) {
return next(value)
}
const newFrame = {...frame, history: [...history, arg]}
if(isFrame(value)) {
runFrame(value, null, function continuation(result) {
runFrame(newFrame, result, next)
})
}
else if(typeof value === "function") {
value(function continuation(result) {
runFrame(newFrame, result, next)
})
}
else {
runFrame(newFrame, value, next)
}
}
function start(genFunc, next) {
runFrame(call(genFunc), null, next)
}
function callcc(genFunc) {
return function (capturedCont) {
function jump(value) {
return next => capturedCont(value)
}
runFrame(
call(genFunc, jump),
null,
capturedCont
)
}
}
let resume
function* main() {
const a = 10
const b = yield callcc(function*(k) {
resume = k
yield k(10)
})
return a + b
}
runFrame(call(main), null, console.log)
// => 20
resume(30)()
// => 40
resume(50)()
// => 60
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment