unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* [Patch] definitions in when,  unless,  do as well as in cond- and case-clauses
@ 2021-06-16 19:11 Linus Björnstam
  2021-06-17  9:06 ` Maxime Devos
  0 siblings, 1 reply; 4+ messages in thread
From: Linus Björnstam @ 2021-06-16 19:11 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 1056 bytes --]

Hi there!

This patch updates some derived conditional forms (and do and and-let*) to support definitions in expression context. Meaning it makes this valid code:

(cond 
  ((pred? arg) 
    (define a (something arg))
    (when (error-case a)
      (error "a is broken"))
    (define b (something2 a))
    (when  (= 3 *log-level*)
      (display "logging something1 and 2 as successful"))
    (define c (something3 b a))
    (when (odd? c)
       (error "something went wrong in something3"))
    c)
  (else 
    ;;chosen by fair dice roll. Guaranteed to be random
    4)))

While awful, is sometimes what the world makes us do. 

The change means cond, case, when and unless behaves like it does in racket. Do was below case, so I changed that as well, and will actually become yet another way guile is superior to racket. 

I did also change the documentation, but I learned english by watching Beverly Hills cop, so that might need some fine touches by a capable english speaker.
            

Best regards
  Linus Björnstam

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Allow-definitions-in-derived-conditional-forms.patch --]
[-- Type: text/x-patch; name="0001-Allow-definitions-in-derived-conditional-forms.patch", Size: 4916 bytes --]

From 7af96162bf531b70e66170864cd536032b1c89c7 Mon Sep 17 00:00:00 2001
From: Linus <bjornstam.linus@fastmail.se>
Date: Wed, 16 Jun 2021 20:47:41 +0200
Subject: [PATCH] Allow definitions in derived conditional forms

This allows definitions in the bodies of when, unless, do, and
 and-let*. It also adds support for definitions in cond- and
case-clauses.

 * doc/ref/api-control.texi (when, unless, cond, case): update
   documentation to reflect changes.
 * module/ice-9/and-let-star.scm: Changed (begin ...) to (let () ...)
 * module/ice-9/boot-9.scm (when, unless, cond, case, do): changed
   (begin ...) to (let () ...)
---
 doc/ref/api-control.texi      | 10 +++++-----
 module/ice-9/and-let-star.scm |  6 +++---
 module/ice-9/boot-9.scm       | 12 ++++++------
 3 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/doc/ref/api-control.texi b/doc/ref/api-control.texi
index 5df5344c5..eaa2b4dbf 100644
--- a/doc/ref/api-control.texi
+++ b/doc/ref/api-control.texi
@@ -152,10 +152,10 @@ documentation:
 
 @example
 (define-syntax-rule (when test stmt stmt* ...)
-  (if test (begin stmt stmt* ...)))
+  (if test (let () stmt stmt* ...)))
 
 (define-syntax-rule (unless condition stmt stmt* ...)
-  (if (not test) (begin stmt stmt* ...)))
+  (if (not test) (let () stmt stmt* ...)))
 @end example
 
 That is to say, @code{when} evaluates its consequent statements in order
@@ -167,11 +167,11 @@ statements if @var{test} is false.
 Each @code{cond}-clause must look like this:
 
 @lisp
-(@var{test} @var{expression} @dots{})
+(@var{test} @var{expression-or-definition} @dots{})
 @end lisp
 
-where @var{test} and @var{expression} are arbitrary expressions, or like
-this
+where @var{test} is an arbitrary expression, and @var{expression-or-definition}
+is an arbitrary expression or a definition, like @code{define}.
 
 @lisp
 (@var{test} => @var{expression})
diff --git a/module/ice-9/and-let-star.scm b/module/ice-9/and-let-star.scm
index 2d53ff384..9427c1733 100644
--- a/module/ice-9/and-let-star.scm
+++ b/module/ice-9/and-let-star.scm
@@ -53,12 +53,12 @@
       ((_ orig-form ((var expr)) . body)
        (identifier? #'var)
        #'(let ((var expr))
-           (and var (begin . body))))
+           (and var (let () . body))))
       ((_ orig-form ((expr)) . body)
-       #'(and expr (begin . body)))
+       #'(and expr (let () . body)))
       ((_ orig-form (var) . body)
        (identifier? #'var)
-       #'(and var (begin . body)))
+       #'(and var (let () . body)))
 
       ;; Handle bad clauses.
       ((_ orig-form (bad-clause . rest) . body)
diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm
index 2323b1ec5..675f38633 100644
--- a/module/ice-9/boot-9.scm
+++ b/module/ice-9/boot-9.scm
@@ -417,10 +417,10 @@ If returning early, return the return value of F."
 (include-from-path "ice-9/quasisyntax")
 
 (define-syntax-rule (when test stmt stmt* ...)
-  (if test (begin stmt stmt* ...)))
+  (if test (let () stmt stmt* ...)))
 
 (define-syntax-rule (unless test stmt stmt* ...)
-  (if (not test) (begin stmt stmt* ...)))
+  (if (not test) (let () stmt stmt* ...)))
 
 (define-syntax else
   (lambda (x)
@@ -461,7 +461,7 @@ If returning early, return the return value of F."
                          ((else e e* ...)
                           (lambda (tail)
                             (if (null? tail)
-                                #'((begin e e* ...))
+                                #'((let () e e* ...))
                                 (bad-clause "else must be the last clause"))))
                          ((else . _) (bad-clause))
                          ((test => receiver)
@@ -488,7 +488,7 @@ If returning early, return the return value of F."
                          ((test e e* ...)
                           (lambda (tail)
                             #`((if test
-                                   (begin e e* ...)
+                                   (let () e e* ...)
                                    #,@tail))))
                          (_ (bad-clause))))
                      #'(clause clauses ...))))))))
@@ -534,7 +534,7 @@ If returning early, return the return value of F."
                                ((=> receiver ...)
                                 (bad-clause
                                  "wrong number of receiver expressions"))
-                               ((e e* ...) #'(begin e e* ...))
+                               ((e e* ...) #'(let () e e* ...))
                                (_ (bad-clause)))))
                          (syntax-case #'test (else)
                            ((datums ...)
@@ -585,7 +585,7 @@ If returning early, return the return value of F."
                (begin
                  (if #f #f)
                  expr ...)
-               (begin
+               (let ()
                  command
                  ...
                  (loop (do "step" var step ...)
-- 
2.25.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Patch] definitions in when,  unless,  do as well as in cond- and case-clauses
  2021-06-16 19:11 [Patch] definitions in when, unless, do as well as in cond- and case-clauses Linus Björnstam
@ 2021-06-17  9:06 ` Maxime Devos
  2021-06-17 12:57   ` Linus Björnstam
  0 siblings, 1 reply; 4+ messages in thread
From: Maxime Devos @ 2021-06-17  9:06 UTC (permalink / raw)
  To: Linus Björnstam, guile-devel

[-- Attachment #1: Type: text/plain, Size: 1134 bytes --]

Linus Björnstam schreef op wo 16-06-2021 om 21:11 [+0200]:
> Hi there!
> 
> This patch updates some derived conditional forms (and do and and-let*)
> to support definitions in expression context. Meaning it makes this valid code:
> 
> (cond 
>   ((pred? arg) 
>     (define a (something arg))
>     (when (error-case a)
>       (error "a is broken"))  [...]

This seems a useful change to me. However, this is not valid R6RS.
From <http://www.r6rs.org/final/r6rs.pdf>:

(cond hcond clause1i hcond clause2i . . . ) syntax
=> auxiliary syntax
else auxiliary syntax
Syntax: Each hcond clausei must be of the form
(htesti hexpression1i . . . )
where htesti is an expression. Alternatively, a
hcond clausei may be of the form
(htesti => hexpressioni)

This seems a compatibility pitfall, so maybe note
in the documentation that using definitions in the clauses
is a Guile and Racket extension and not standard R6RS?

(I try to write Scheme code as R6RS / R7RS library & define-library
forms, importing mostly R6RS / R7RS & SRFI libraries, though I occasionally
use a Guile extension.)

Greetings,
Maxime

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Patch] definitions in when,   unless,   do as well as in cond- and case-clauses
  2021-06-17  9:06 ` Maxime Devos
@ 2021-06-17 12:57   ` Linus Björnstam
  2021-06-17 13:54     ` Maxime Devos
  0 siblings, 1 reply; 4+ messages in thread
From: Linus Björnstam @ 2021-06-17 12:57 UTC (permalink / raw)
  To: Maxime Devos, guile-devel

Guile already does definitions in expression context in the bodies of lambda and let-variants. I think this is not a big problem since any valid r6rs code is still valid guile.

The discussion is in my opinion whether guile's r6rs modules should enforce this behaviour. That might be a good thing, even though we will provide 2 cons and case forms to do that.

-- 
  Linus Björnstam

On Thu, 17 Jun 2021, at 11:06, Maxime Devos wrote:
> Linus Björnstam schreef op wo 16-06-2021 om 21:11 [+0200]:
> > Hi there!
> > 
> > This patch updates some derived conditional forms (and do and and-let*)
> > to support definitions in expression context. Meaning it makes this valid code:
> > 
> > (cond 
> >   ((pred? arg) 
> >     (define a (something arg))
> >     (when (error-case a)
> >       (error "a is broken"))  [...]
> 
> This seems a useful change to me. However, this is not valid R6RS.
> From <http://www.r6rs.org/final/r6rs.pdf>:
> 
> (cond hcond clause1i hcond clause2i . . . ) syntax
> => auxiliary syntax
> else auxiliary syntax
> Syntax: Each hcond clausei must be of the form
> (htesti hexpression1i . . . )
> where htesti is an expression. Alternatively, a
> hcond clausei may be of the form
> (htesti => hexpressioni)
> 
> This seems a compatibility pitfall, so maybe note
> in the documentation that using definitions in the clauses
> is a Guile and Racket extension and not standard R6RS?
> 
> (I try to write Scheme code as R6RS / R7RS library & define-library
> forms, importing mostly R6RS / R7RS & SRFI libraries, though I occasionally
> use a Guile extension.)
> 
> Greetings,
> Maxime
> 
> Attachments:
> * signature.asc



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Patch] definitions in when,  unless,  do as well as in cond- and case-clauses
  2021-06-17 12:57   ` Linus Björnstam
@ 2021-06-17 13:54     ` Maxime Devos
  0 siblings, 0 replies; 4+ messages in thread
From: Maxime Devos @ 2021-06-17 13:54 UTC (permalink / raw)
  To: Linus Björnstam, guile-devel

[-- Attachment #1: Type: text/plain, Size: 999 bytes --]

Linus Björnstam schreef op do 17-06-2021 om 14:57 [+0200]:
> Guile already does definitions in expression context in
> the bodies of lambda and let-variants. I think this is
> not a big problem since any valid r6rs code is still valid guile.

‘Guile already does definitions in expression context in [...]’:
good point.

> The discussion is in my opinion whether guile's r6rs modules should
> enforce this behaviour. That might be a good thing, even though we
> will provide 2 cons and case forms to do that.

Pro: if your code works when using r6rs modules (in Guile), then it should
work on any r6rs-conforming implementation.

Con: (@ (guile) cond) != (@ (rnrs base) cond), which can be surprising.

Con: ‘I know this usage isn't universally portable, but I'll cross that
bridge when needed. All the Scheme I care about do have this extension.
If a Scheme doesn't have this extension, I'll just patch that Scheme
(free software for the win!)’

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-06-17 13:54 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-16 19:11 [Patch] definitions in when, unless, do as well as in cond- and case-clauses Linus Björnstam
2021-06-17  9:06 ` Maxime Devos
2021-06-17 12:57   ` Linus Björnstam
2021-06-17 13:54     ` Maxime Devos

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).