[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: GNU Guile 2.9.5 Released [beta]

From: Andy Wingo
Subject: Re: GNU Guile 2.9.5 Released [beta]
Date: Sun, 05 Jan 2020 21:15:52 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux)

On Sun 01 Dec 2019 21:41, Chris Vine <address@hidden> writes:

> Is this rewrite, and the new with-exception-handler procedure, an
> opportunity to think about standardization of guile's implementation of
> the R6RS/R7RS 'guard' form, or at least think about what is wanted for
> 'guard'?
> The formal semantics (including specimen implementation) of 'guard' for
> R6RS with the corrigendum to §7.1 of the standard library at
>, and for R7RS without corrigendum
> (at §4.2.7 and §7.3, page 72 of the standard), is:
> (i) to evaluate the guard body within a block with its own continuation
> (as constructed by call/cc);
> (ii) if an exception is thrown, evaluate the handler (and its cond
> clauses) in the dynamic context of the original caller of 'guard' via
> that continuation;
> (iii) if no matching cond clause and no else clause is found, return to
> the dynamic environment of the original 'raise' and re-raise the
> exception with 'raise-continuable', even for non-continuable
> exceptions.
> If a fully conforming R6RS/R7RS implementation runs this code:
>   (guard (exn [(equal? exn 5) #f])
>     (guard (exn [(equal? exn 6) 'never-reached])
>       (dynamic-wind
>         (lambda () (display "in") (newline))
>         (lambda () (raise 5))
>         (lambda () (display "out") (newline)))))
> the code evaluates to #f and should print this:
>   in
>   out
>   in
>   out
> In chez scheme it does so.  In most other implementations (including
> guile and racket) it seems to print:
>   in
>   out

I really think the standards messed up regarding the specification of

But those ships have sailed and are now lost at sea.  Guile currently
has two separate implementations of "guard" for SRFI-34 (used by R7RS)
and R6RS.  It would seem that besides not respecting the specification,
the R6RS one is broken, as it expects the "cond" clauses to evaluate to
a single value.

For SRFI-34 (and R7RS), after the exception refactor, I did a re-write
to give a shot at implementing the specified behavior.  It works with a
caveat:  because it uses delimited continuations as the rewind
mechanism, and Guile has a limitation that some delimited continuations
can't be rewound (if the continuation bounces through C), then
re-raising the exception fails because the context can't be rewound.
This can cause previously working programs to break!

Which makes me think, if call/cc (rather than call-with-prompt /
abort-to-prompt) is necessary to implement "guard", we are in a bad
place and we should specify something else.

I have long thought that the right thing to do is this: we evaluate the
"cond" tests in the dynamic environment of the "raise".  Then if a test
succeeds, we unwind and run the corresponding consequent.  That way
there's no rewinding.  Here's an implementation:

  (define-syntax guard
    (syntax-rules (else)
      ((guard (var (t e e* ...) ...) body body* ...)
       (let ((tag (make-prompt-tag)))
          (lambda ()
             (lambda (var)
                (t (abort-to-prompt tag (lambda () e e* ...)))
               (raise var))
             (lambda ()
               body body* ...)))
          (lambda (k thunk)

Though I think it might be reasonable to use "raise-continuable" instead
of "raise" if nothing matches.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]