Am Mi., 10. Juni 2020 um 23:46 Uhr schrieb John Cowan <xxxxxx@ccil.org>:
>
> I don't see that there's much difference between the protocol conversions lisp->, values->, lisp-values->, and exception->; they should have systematic names. I prefer them to be procedures rather than a mixture of procedures and syntax, and I think the extended -> convention is perfectly fine once it is explained. The particular choices of name components I admit are not very good, and if anyone has different ones, I'll absolutely consider them.
As you know, I have some issues with the "values->..." naming as I
have already said. Moreover, a systematic name doesn't help that much
here because the first argument to the "values->" procedures is very
different, namely a producer. I think that should be reflected by the
name. And because it means that "values->" isn't the (lossy) inverse
in the simplest sense.
I have to admit, though, that I currently have no good name in mind,
which would match "call-with-values" in the report, which also takes a
producer procedure.
While my issue with "values->" is a minor one, the naming of
"exception->either" is a major one IMHO. As "exception->either" is
more of a converse to "either-ref", I wouldn't even put it in the
"Conversion" section as it really different from all the other
procedures there. And when one puts it into another section for
clarity, say "Exceptions", it wouldn't look like a strange mixture
between procedures and syntax, and, moreover, we are free to choose a
better name. Why don't you like "either-guard"?
> The problem with using guard to implement exception->either or anything like it is that it breaks if something inside the thunk/body does a raise-continuable which is to be intercepted by a handler that catches it and returns values to the caller. A guard expression's default action in the absence of an else-clause will change that to a raise instead, which means there is no way back (an attempt to return from the handler will just raise another exception). Using an else-clause is even worse, because then the call/cc makes it outright impossible to return.
That's a very good point. So what about the following?
(define-syntax either-guard
(syntax-rules ()
((either-guard pred? . body)
(guard (exc ((pred? exc) (left exc)) (else (raise-continuable
exc))) (call-with-values (lambda () . body) right)))))
In the default case, this will reraise `exc` for the exception handler
of the `either-guard` expression. If this exception is caught by that
exception handler and this exception handler returns, by definition of
`raise-continuable`, the control flow will be back in the `else`
clause of the guard, which will then return. Another error will be
raised in case the original exception wasn't continuable, otherwise,
the control flow will jump to where the continuable exception has been
originally raised.