I also based my Zig Lisp interpreter on delimited continuations and had a great time implementing async, resumable exceptions, dynamically scoped variables, and so on, on top of that.
The single-stepping continuation-shuffling evaluation paradigm also made it really easy to expose evaluations as objects and stepping as a function. A simple form like
(set! e (run (+ 1 1))
stores an evaluation—whose continuation and lexical environment can both be inspected and serialized—and
(step! e)
does a single evaluation step. This lets you implement not just yield-based cooperative concurrency in "user space" but something like green threads with a preemptive scheduler.
Here you can see how the delimited continuation control allows binding to JavaScript's Promise API in a way that lets you treat promises as blocking computations:
Wow that's an awesome idea. I never thought of that. Never occurred to me to expose the machine cycling mechanism.
Send-with-default also seems useful. I was thinking about how to handle the case where the bottom of the stack is reached. Other languages just error out if that happens. I suppose returning a value is just as reasonable.
The single-stepping continuation-shuffling evaluation paradigm also made it really easy to expose evaluations as objects and stepping as a function. A simple form like
stores an evaluation—whose continuation and lexical environment can both be inspected and serialized—and does a single evaluation step. This lets you implement not just yield-based cooperative concurrency in "user space" but something like green threads with a preemptive scheduler.Here you can see how the delimited continuation control allows binding to JavaScript's Promise API in a way that lets you treat promises as blocking computations:
https://github.com/mbrock/wisp/blob/master/web/js.wisp
You might be interested in seeing e.g. the implementation of SEND-WITH-DEFAULT! which is one of the control control primitives:
https://github.com/mbrock/wisp/blob/b8e29dba0ea61ebaf2db5e3e...
The evaluator itself is in core/step.zig if you want to check it out.