Since long time ago, I was thinking if Sagittarius can have some nice
async/await equivalent things. I'm using Java/Kotlin at my work,
occasionally TypeScript, they, execpt Java, have nice async/await
thing. So, I asked my new shiny friends, Copilot or ChatGPT, if it's
possible to implement it with continuation. And the answer was yes,
also it'd be cleaner if I use delimited continuation.
Now, I remember that SRFI-226 defines delimited continuation. And I vaguely remember one of the discussions saying it can be implemented with continuation prommpt and composable continuation. I've been avoiding to touching the continuation, but it seems it's time for me to have some courage.
With my shallow understanding, composable continuation requires continuation prompt, so I decided to implement continuation prompt first. A continuation prompt can be implemented as a boundary frame. Currently, Sagittarius's call frame is implementented like this:
[ cont 0 ] <-- top
[ cont 1 ]
[ cont 2 ]
[ boundary ] <-- when C calling Scheme procedure
[ cont 3 ]
:
[ cont n ] <-- bottom
Now, I should be able to implement prompt as an extra frame like this:
[ cont 0 ] <-- top
[ cont 1 ]
[ cont 2 ]
[ prompt ] <-- prompt frame
[ cont 3 ]
:
[ cont n ] <-- bottom
There's a very good reason why I should do this. Sagittarius' compiler
optimises let with very advanced (I want to believe) way. It takes
frame size into account. This means, I can't add extra field into the
call frame structure. Because of this reason, I can't annotate the
call frame with prompt tag by adding an extra struct member. The
boundary frame is already using one of the members to hold a mark. In
other words, I can use one member to hold prompt information.
Now, inserting prompt seems easy job, then next step,
abort-current-continuation. It seems this is required to implement
delimited continuation. Reading the document doen't really click what
it does. So checked the behaviour with Racket. Started with the very
simple example below.
(call-with-continuation-prompt
(lambda ()
(abort-current-continuation (default-continuation-prompt-tag) 1)
(display 'not-reached) (newline))
(default-continuation-prompt-tag)
values)
;; -> 1
My easily get hallucinated brain understood that abort-current-continuation
aborts the current continuation up to the specified prompt tag and invokes
the abort-handler... this is what the document says... If I draw a diagram
then it looks like this
[ cont 0 ] <-- abort/cc
[ cont 1 ]
[ cont 2 ]
[ prompt ] <-- target == after ==> ;; the rest of the call frame
[ cont 3 ] [ cont 3 ]
: :
[ cont n ] [ cont n ]
Okay, it looks easy enough to do it.
(Until I fell into a lots of pitfalls...)