unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* Add internal definitions to derived forms
@ 2022-11-09 15:32 Linus Björnstam
  2022-11-09 15:46 ` Damien Mattei
  2022-11-17  7:25 ` lloda
  0 siblings, 2 replies; 9+ messages in thread
From: Linus Björnstam @ 2022-11-09 15:32 UTC (permalink / raw)
  To: guile-devel

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

Hi there!

This commit adds internal definitions to derived conditional forms, with-fluids and and-let*. This means the bodies of when, unless and with-fluids, and the clause bodies of case and cond behave like a lambda body. 

There is no performance hit since guile optimizes a (let () ...) without internal definitions to a begin (i.e: no new lexical context is created).

best regards
  Linus Björnstam

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

From 7eeb91b822334b151c5b4a15ce9528a2a655d914 Mon Sep 17 00:00:00 2001
From: Linus <bjornstam.linus@fastmail.se>
Date: Wed, 9 Nov 2022 16:15:18 +0100
Subject: [PATCH] Add internal definitions to derived forms

This commit adds internal definitions to the following derived
forms: when, unless, cond, case, with-fluids, and and-let*.

 * doc/ref/api-control.texi (Conditionals): Update the syntax and docs
   of when, unless, cond, and case.
 * module/ice-9/and-let-star.scm (and-let*): Changed begins to let.
 * module/ice-9/boot-9.scm (cond, case, when, unless, with-fluids):
   Changed begins to let.
---
 doc/ref/api-control.texi      | 25 +++++++++++++------------
 module/ice-9/and-let-star.scm |  6 +++---
 module/ice-9/boot-9.scm       | 12 ++++++------
 3 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/doc/ref/api-control.texi b/doc/ref/api-control.texi
index 087e795..ece6a60 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 test 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{body} @dots{})
 @end lisp
 
-where @var{test} and @var{expression} are arbitrary expressions, or like
-this
+where @var{test} is an arbitrary expression and @var{body} is a
+lambda-like body, or like this
 
 @lisp
 (@var{test} => @var{expression})
@@ -217,7 +217,7 @@ result of the @code{cond}-expression.
 @var{key} may be any expression, and the @var{clause}s must have the form
 
 @lisp
-((@var{datum1} @dots{}) @var{expr1} @var{expr2} @dots{})
+((@var{datum1} @dots{}) @var{body} @dots{})
 @end lisp
 
 or
@@ -229,7 +229,7 @@ or
 and the last @var{clause} may have the form
 
 @lisp
-(else @var{expr1} @var{expr2} @dots{})
+(else @var{expr1} @var{body} @dots{})
 @end lisp
 
 or
@@ -239,13 +239,14 @@ or
 @end lisp
 
 All @var{datum}s must be distinct.  First, @var{key} is evaluated.  The
-result of this evaluation is compared against all @var{datum} values using
-@code{eqv?}.  When this comparison succeeds, the expression(s) following
-the @var{datum} are evaluated from left to right, returning the value of
-the last expression as the result of the @code{case} expression.
+result of this evaluation is compared against all @var{datum} values
+using @code{eqv?}.  When this comparison succeeds, the @var{body}
+following the @var{datum} is evaluated like the body of a lambda,
+returning the value of the last expression as the result of the
+@code{case} expression.
 
 If the @var{key} matches no @var{datum} and there is an
-@code{else}-clause, the expressions following the @code{else} are
+@code{else}-clause, the @var{body} following the @code{else} is
 evaluated.  If there is no such clause, the result of the expression is
 unspecified.
 
diff --git a/module/ice-9/and-let-star.scm b/module/ice-9/and-let-star.scm
index 2d53ff3..9427c17 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 a46145e..dc35370 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 ...)
@@ -674,7 +674,7 @@ If returning early, return the return value of F."
          #`(let ((fluid-tmp fluid) ...)
              (let ((val-tmp val) ...)
                #,(emit-with-fluids #'((fluid-tmp val-tmp) ...)
-                                   #'(begin exp exp* ...)))))))))
+                                   #'(let () exp exp* ...)))))))))
 
 (define-syntax current-source-location
   (lambda (x)
-- 
2.25.1


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

* Re: Add internal definitions to derived forms
  2022-11-09 15:32 Add internal definitions to derived forms Linus Björnstam
@ 2022-11-09 15:46 ` Damien Mattei
  2022-11-17  7:25 ` lloda
  1 sibling, 0 replies; 9+ messages in thread
From: Damien Mattei @ 2022-11-09 15:46 UTC (permalink / raw)
  To: Linus Björnstam; +Cc: guile-devel

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

thanks,hope it will be in a next stable release of Guile
regards,
damien

On Wed, Nov 9, 2022 at 4:34 PM Linus Björnstam <linus.bjornstam@veryfast.biz>
wrote:

> Hi there!
>
> This commit adds internal definitions to derived conditional forms,
> with-fluids and and-let*. This means the bodies of when, unless and
> with-fluids, and the clause bodies of case and cond behave like a lambda
> body.
>
> There is no performance hit since guile optimizes a (let () ...) without
> internal definitions to a begin (i.e: no new lexical context is created).
>
> best regards
>   Linus Björnstam

[-- Attachment #2: Type: text/html, Size: 1069 bytes --]

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

* Re: Add internal definitions to derived forms
  2022-11-09 15:32 Add internal definitions to derived forms Linus Björnstam
  2022-11-09 15:46 ` Damien Mattei
@ 2022-11-17  7:25 ` lloda
  2022-11-18  9:04   ` Linus Björnstam
  1 sibling, 1 reply; 9+ messages in thread
From: lloda @ 2022-11-17  7:25 UTC (permalink / raw)
  To: Linus Björnstam; +Cc: guile-devel


Hi Linus,

I don't understand the following change since at least one expression is required in these clauses.

 @lisp
 (@var{test} => @var{expression})
@@ -217,7 +217,7 @@ result of the @code{cond}-expression.
 @var{key} may be any expression, and the @var{clause}s must have the form
 
 @lisp
-((@var{datum1} @dots{}) @var{expr1} @var{expr2} @dots{})
+((@var{datum1} @dots{}) @var{body} @dots{})
 @end lisp

Regards

  Daniel


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

* Re: Add internal definitions to derived forms
  2022-11-17  7:25 ` lloda
@ 2022-11-18  9:04   ` Linus Björnstam
  2022-11-18  9:27     ` Lassi Kortela
  0 siblings, 1 reply; 9+ messages in thread
From: Linus Björnstam @ 2022-11-18  9:04 UTC (permalink / raw)
  To: lloda; +Cc: guile-devel

Hi!

Well, the point of the change is to make it so that things other than expressions are allowed. I change it to say @var{body}, and then later clarify that @var{test} is an arbitrary expression and @var{body} is a lambda-like body. 

Which when reading it now sounds... not very good. 

Would "is like the body of a lambda" be a better wording? That would imply that at least one expression is required. English is very much not my first language, and documentation changes are the ones that I fear the most...

best regards
  Linus Björnstam

On Thu, 17 Nov 2022, at 08:25, lloda wrote:
> Hi Linus,
>
> I don't understand the following change since at least one expression 
> is required in these clauses.
>
>  @lisp
>  (@var{test} => @var{expression})
> @@ -217,7 +217,7 @@ result of the @code{cond}-expression.
>  @var{key} may be any expression, and the @var{clause}s must have the form
> 
>  @lisp
> -((@var{datum1} @dots{}) @var{expr1} @var{expr2} @dots{})
> +((@var{datum1} @dots{}) @var{body} @dots{})
>  @end lisp
>
> Regards
>
>   Daniel



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

* Re: Add internal definitions to derived forms
  2022-11-18  9:04   ` Linus Björnstam
@ 2022-11-18  9:27     ` Lassi Kortela
  2022-11-18  9:50       ` Linus Björnstam
  0 siblings, 1 reply; 9+ messages in thread
From: Lassi Kortela @ 2022-11-18  9:27 UTC (permalink / raw)
  To: guile-devel

> Would "is like the body of a lambda" be a better wording?

R7RS section 3.5. says:

(lambda <formals> <definition>* <expression>* <tail expression>)

The <definition>* are the stuff you are adding.



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

* Re: Add internal definitions to derived forms
  2022-11-18  9:27     ` Lassi Kortela
@ 2022-11-18  9:50       ` Linus Björnstam
  2022-11-18 10:22         ` Lassi Kortela
  0 siblings, 1 reply; 9+ messages in thread
From: Linus Björnstam @ 2022-11-18  9:50 UTC (permalink / raw)
  To: Lassi Kortela, guile-devel

On Fri, 18 Nov 2022, at 10:27, Lassi Kortela wrote:
>> Would "is like the body of a lambda" be a better wording?
>
> R7RS section 3.5. says:
>
> (lambda <formals> <definition>* <expression>* <tail expression>)
>
> The <definition>* are the stuff you are adding.

Not quite. Guile extends the lambda body (and by extension let-forms) to allow mixed definitions and expressions:

(lambda () 
  (display "Heippa!")
  (define routsi #t)
  (and (read) routsi))

which expands to, more or less, a letrec*. All in accordance to the paper fixing letrec(reloaded).

Thus saying that the cond clause body is like a lambda body is probably the simplest way to express it. 

best regards
Linus Björnstam



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

* Re: Add internal definitions to derived forms
  2022-11-18  9:50       ` Linus Björnstam
@ 2022-11-18 10:22         ` Lassi Kortela
  2022-11-18 12:53           ` Linus Björnstam
  0 siblings, 1 reply; 9+ messages in thread
From: Lassi Kortela @ 2022-11-18 10:22 UTC (permalink / raw)
  To: guile-devel

> Not quite. Guile extends the lambda body (and by extension let-forms) to allow mixed definitions and expressions:
> 
> (lambda ()
>    (display "Heippa!")
>    (define routsi #t)
>    (and (read) routsi))
> 
> which expands to, more or less, a letrec*. All in accordance to the paper fixing letrec(reloaded).
> 
> Thus saying that the cond clause body is like a lambda body is probably the simplest way to express it.

R7RS defines the syntax of `let` et.al. as follows (section 3.5):

(let (<binding spec>*) <tail body>)

Where:

<tail body> = <definition>* <tail sequence>
<tail sequence> = <expression>* <tail expression>

So their definition of lambda:

(lambda <formals> <definition>* <expression>* <tail expression>)

could be abbreviated:

(lambda <formals> <tail body>)

I haven't read "Fixing letrec" but it looks like Guile intents to 
redefine <tail body> as follows:

<tail body> = <definition-or-expression>* <tail expression>
<definition-or-expression>* = <definition> | <expression>

R6RS appears to use <tail body> in the same sense as R7RS.



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

* Re: Add internal definitions to derived forms
  2022-11-18 10:22         ` Lassi Kortela
@ 2022-11-18 12:53           ` Linus Björnstam
  2022-11-18 13:18             ` Lassi Kortela
  0 siblings, 1 reply; 9+ messages in thread
From: Linus Björnstam @ 2022-11-18 12:53 UTC (permalink / raw)
  To: Lassi Kortela, guile-devel

On Fri, 18 Nov 2022, at 11:22, Lassi Kortela wrote:
> R7RS defines the syntax of `let` et.al. as follows (section 3.5):
>
> (let (<binding spec>*) <tail body>)
>
> Where:
>
> <tail body> = <definition>* <tail sequence>
> <tail sequence> = <expression>* <tail expression>
>
> So their definition of lambda:
>
> (lambda <formals> <definition>* <expression>* <tail expression>)
>
> could be abbreviated:
>
> (lambda <formals> <tail body>)
>
> I haven't read "Fixing letrec" but it looks like Guile intents to 
> redefine <tail body> as follows:
>
> <tail body> = <definition-or-expression>* <tail expression>
> <definition-or-expression>* = <definition> | <expression>
>
> R6RS appears to use <tail body> in the same sense as R7RS.

That is a better way to write it indeed. clause-body being equal to a lambda body. 

Thank you.



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

* Re: Add internal definitions to derived forms
  2022-11-18 12:53           ` Linus Björnstam
@ 2022-11-18 13:18             ` Lassi Kortela
  0 siblings, 0 replies; 9+ messages in thread
From: Lassi Kortela @ 2022-11-18 13:18 UTC (permalink / raw)
  To: Linus Björnstam, guile-devel

> That is a better way to write it indeed. clause-body being equal to a lambda body.
> 
> Thank you.

No problem.

Nb. I made an oversight - the section of R7RS with the grammar I quoted 
says:

"These were derived from rules in the grammar given in chapter 7 by 
replacing some occurrences of <body> with <tail body>, some occurrences 
of <expression> with <tail expression>, and some occurrences of 
<sequence> with <tail sequence>."

So the more general names are <expression>, <sequence>, and <body>.



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

end of thread, other threads:[~2022-11-18 13:18 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-09 15:32 Add internal definitions to derived forms Linus Björnstam
2022-11-09 15:46 ` Damien Mattei
2022-11-17  7:25 ` lloda
2022-11-18  9:04   ` Linus Björnstam
2022-11-18  9:27     ` Lassi Kortela
2022-11-18  9:50       ` Linus Björnstam
2022-11-18 10:22         ` Lassi Kortela
2022-11-18 12:53           ` Linus Björnstam
2022-11-18 13:18             ` Lassi Kortela

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 read-only IMAP folder(s) and NNTP newsgroup(s).