[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
> http://www.r6rs.org/r6rs-errata.html, 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
"guard":
http://scheme-reports.org/mail/scheme-reports/msg03247.html
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)))
(call-with-prompt
tag
(lambda ()
(with-exception-handler
(lambda (var)
(cond
(t (abort-to-prompt tag (lambda () e e* ...)))
...)
(raise var))
(lambda ()
body body* ...)))
(lambda (k thunk)
(thunk)))))))
Though I think it might be reasonable to use "raise-continuable" instead
of "raise" if nothing matches.
WDYT?
Andy
- Re: GNU Guile 2.9.5 Released [beta],
Andy Wingo <=