From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Chris Vine Newsgroups: gmane.lisp.guile.devel Subject: Re: GNU Guile 2.9.5 Released [beta] Date: Sun, 5 Jan 2020 23:26:40 +0000 Message-ID: <20200105232640.8d389c139c7b4993e90938a1@gmail.com> References: <87lfs8kkao.fsf@pobox.com> <20191201204142.0388791e61fa443e615605da@gmail.com> <87eewdu0av.fsf@pobox.com> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="181809"; mail-complaints-to="usenet@blaine.gmane.org" Cc: guile-users@gnu.org, guile-devel@gnu.org To: Andy Wingo Original-X-From: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Mon Jan 06 00:26:43 2020 Return-path: Envelope-to: guile-devel@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1ioFI9-000l51-Gx for guile-devel@m.gmane.org; Mon, 06 Jan 2020 00:26:41 +0100 Original-Received: from localhost ([::1]:46292 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ioFI7-00041J-NO for guile-devel@m.gmane.org; Sun, 05 Jan 2020 18:26:39 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:53959) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ioFHt-00041D-HI for guile-devel@gnu.org; Sun, 05 Jan 2020 18:26:27 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ioFHr-0000JC-JN for guile-devel@gnu.org; Sun, 05 Jan 2020 18:26:25 -0500 Original-Received: from mail-wr1-x431.google.com ([2a00:1450:4864:20::431]:40314) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1ioFHq-0000IC-8T for guile-devel@gnu.org; Sun, 05 Jan 2020 18:26:23 -0500 Original-Received: by mail-wr1-x431.google.com with SMTP id c14so47826368wrn.7; Sun, 05 Jan 2020 15:26:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:cc:subject:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=g7pg3yYrMlIGEuRJZCbRd6C9PvvAxM1DrV99m1lB8Rs=; b=l1eSbMnktmkz4VRN04v/y3H7/faIAx2k3G8rdGODKqlufbFnJzNycb2JKwM+FJLN9+ 2lYo8UO3VyOkq168G2WbQWA6xQAXU4SbXH1RaFFMArfvLP18cWyoLyxWqspHlcer8XG/ OutjYXJWvedCIsWPdExWJOvmt8/Czc+wfw/bF/hBcZWjVflofYrR5AeQgQNqVah3jljq 6QFjfFsvRNaBTwo1guMaMNfY3J5lILw6mJp8A51j8oR42VTmb4Sf26+E0QEFzUNGzjz7 Ea35pC2gnC8wNqcAE1rM+75B629l8vlhJfYOuGH8QNR1CeDjQnJtoz+l/90ZUNAGUsNV mj8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=g7pg3yYrMlIGEuRJZCbRd6C9PvvAxM1DrV99m1lB8Rs=; b=RAoj0u5SC1/ur4lUkluCYobKd+4y5KjOLFuAE9JYhnXs3F+bEojQq0rn0j+mdxSScP ItSHi+NfWNQE3brwa0YSi9sdSB0L1WpKJ4BMAER0NVYnLIoHOfTcJ6s3vKe56lvWYSUp 6oMB7oQfJ7SBDQfmZutQtUiQNmmOPhPUo1/3IV+SscIIwmtKeQ7TYLHvUjcgvHJisNRf XmftsCQqc1jzHZpanykBpwh3T9VeVtxUL3wRwSjcjRN9NfOc+6jecCh8Qlzp7jGTM8mD 794GKuv5tV1qMuwrCp44QH4vGb1556wyHEbMfTdGyF+RJitJcYk4NqpZRT48Oco0DpRz seIA== X-Gm-Message-State: APjAAAUOtqfK/RJRmtqLRMSCIltyzPU2ys+XeBoQWNeGq8P3JzMRqV56 alkBNNpzaOLV+iBkBVBR8sneTxad X-Google-Smtp-Source: APXvYqxH+k5Mca7lkHaSxOyD56C/0/pL3N9oUIyt23IFNuhsPQbHUquOxJyA6o/7nXZ9SkSttKeexw== X-Received: by 2002:a5d:4f90:: with SMTP id d16mr96023857wru.395.1578266780333; Sun, 05 Jan 2020 15:26:20 -0800 (PST) Original-Received: from bother.homenet ([91.110.243.20]) by smtp.gmail.com with ESMTPSA id w19sm20450372wmc.22.2020.01.05.15.26.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 05 Jan 2020 15:26:19 -0800 (PST) Original-Received: from bother.homenet (localhost [127.0.0.1]) by bother.homenet (Postfix) with SMTP id 1DEC226030A; Sun, 5 Jan 2020 23:26:40 +0000 (GMT) In-Reply-To: <87eewdu0av.fsf@pobox.com> X-Mailer: Sylpheed 3.7.0 (GTK+ 2.24.32; x86_64-unknown-linux-gnu) X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::431 X-BeenThere: guile-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Developers list for Guile, the GNU extensibility library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Original-Sender: "guile-devel" Xref: news.gmane.org gmane.lisp.guile.devel:20227 Archived-At: On Sun, 05 Jan 2020 21:15:52 +0100 Andy Wingo wrote: > On Sun 01 Dec 2019 21:41, Chris Vine 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 =A77.1 of the standard library at > > http://www.r6rs.org/r6rs-errata.html, and for R7RS without corrigendum > > (at =A74.2.7 and =A77.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 >=20 > I really think the standards messed up regarding the specification of > "guard": >=20 > http://scheme-reports.org/mail/scheme-reports/msg03247.html >=20 > 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. >=20 > 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! >=20 > 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. >=20 > 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: >=20 > (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))))))) >=20 > Though I think it might be reasonable to use "raise-continuable" instead > of "raise" if nothing matches. >=20 > WDYT? I have a 'try' macro which adopts the approach that if an exception arises, the macro unwinds from the dynamic environment of the code where the exception arose to the dynamic environment of the call to 'try', evaluates the cond clauses in that environment, and then if no cond clause matches re-raises the exception in that environment with 'raise' (rather than 'raise-continuable'). In other words, it does stack unwinding in the same way as exception implementations in almost all other mainstream languages which use exceptions. It would be trivial to implement this with guile-3.0's with-exception-handler with its unwind? argument set to true. That is how I think it should be done, but it is inconsistent with the specification for R6RS/R7RS 'guard'. On the other hand, as you say it does not seem feasible to implement in guile the R6RS/R7RS requirement to unwind to the environment of the call to 'guard' when evaluating the cond clauses, and then return to the environment of the original exception in order to re-raise if no cond clause matches. Furthermore such a return is only relevant if the exception is to be re-raised with 'raise-continuable' instead of 'raise': it is pointless if the exception is re-raised with 'raise' because with 'raise' you can never get back there again. So it appears that the choice for 'guard' in guile is between adopting the approach of my 'try' macro (unwind and re-raise if necessary with 'raise'), or to do what you propose and not to unwind the stack when evaluating the cond clause conditionals, and if no cond conditional matches to re-raise with 'raise-continuable', or if one matches to unwind and evaluate the cond consequent in the dynamic environment of 'guard'. Or put another way, the choice is either to fail to comply with R6RS/R7RS by re-raising with 'raise' instead of 'raise-continuable' (my 'try' macro), or to fail to comply with the requirement to evaluate the cond clause conditionals in the dynamic environment of the call to 'guard' (your proposal). Naturally I prefer the first approach, but others may well disagree. I am somewhat influenced by my view of 'raise-continuable'. I don't like it - how often does anyone use continuable exceptions, which seem to be a reimplementation of common lisp restarts? The only place where I have seen restarts used is in building REPLs. First, most other experience leads me to believe that the place to decide whether recovery is possible (and how to do it) in the event of an exceptional situation arising is at the site of the exceptional situation, not somewhere up the stack which varies dynamically and could be anywhere. Secondly, continuable exceptions can break resource management using dynamic winds or re-throws - for example once you close a port on exit it is closed and cannot be re-opened on re-entry without loss of information, if it can be re-opened at all. I see little practical use for them. Chris