Op 13-04-2023 om 22:18 schreef Marc Nieper-Wißkirchen:
Am Do., 13. Apr. 2023 um 18:00 Uhr schrieb Maxime Devos <maximede...@telenet.be>:Op 13-04-2023 om 17:29 schreef Marc Nieper-Wißkirchen:Hi Maxime, Thanks for sharing your code! I don't see many delimited continuations at work, though. The continuation-related primitive in your code is basically abort-to-prompt, which is here of equal power as C's longjmp or other languages throw/catch (and reflects the most typical use of Scheme's classical call/cc). But maybe I miss something in your code.I won't comment on longjmp because that's too long ago for me > In Scheme terms, this just describes one-shot escaping continuations.
In that case, I can tell you that here it's _not_ of equal power as one-shot escape continuations, because the code relies on _reinstating_ the continuation:
Maybe it is just throw/catch in disguise, but I don't see it -- on line 57 + 66/70, the continuation is reinstated, which isn't something you can do with throw/catch; you need raise-continuable/guard for that.Ah, I should have taken a closer look at Guile's primitives. I only Racket's and the ones I wrote down in SRFI 226 by heart. Guile's abort-to-prompt does not only abort to the prompt but also captures the delimited continuation, which I didn't know. I looked for some instance of call/cc or call-with-delimited-continuation or the like.I'm not sure if raise-continuable/guard is sufficient because there is also a little state ('visiting' and 'visited') and I wanted to avoid 'set!', but perhaps I'm just implementing 'set!' in terms of delimited continuations here.Raise-continuable does no magic; guard uses continuations but mostly only to install the correct dynamic environment (and to be able the handler to escape with-exception-handler).
In Guile, this is false. Guile uses the wrong dynamic environment (as an optimisation): IIUC, for the guard test expressions are evaluated in the dynamic environment of the 'raise'/'raise-continuable' invocation, instead of the dynamic environment of the (guard ...) form.
Otherwise correct, but irrelevant.
If catch/throw is not enough raise-continuable/guard is neither.
This sounds logically invalid to me, as raise-continuable is strictly more powerful than raise-exception -- you can trivially graft "you can't continue the exception" on top of a continuable exception API, but not the other way around:
;; non-continuable exceptions are more-or-less implemented in terms of ;; continuable exceptions in Guile. The exact implementation ;; is a little different because 'raise' and 'raise-continuable' ;; are combined in a single procedure that accepts a ;; #:continuable? argument, but it isn't different in in any way ;; that matters for this e-mail. (define (raise exception) (raise-continuable exception)(error "you tried to continue the non-continuable exception; don't do that!"))
The state (which you don't modify explicitly with set!) is hidden in the implicit continuation of Scheme's evaluation model.
Basically, IIUC, my point is, that I need the _continuable_ part of raise-continuable to get that implicit continuation. With 'throw/catch', I only get an escape continuation API, but I need to _unescape_, and that's exactly the thing that makes raise-continuable different from raise (or, viewed the other way around: that's the thing that raise removes from raise-continuable).
You may want to look at the "state handler" examples here: https://github.com/mnieper/scheme-libraries/blob/main/test-effect.scm.
That's the kind of thing I was referring to with:"but perhaps I'm just implementing 'set!' in terms of delimited continuations here. "
Greetings, Maxime.
OpenPGP_0x49E3EE22191725EE.asc
Description: OpenPGP public key
OpenPGP_signature
Description: OpenPGP digital signature