On Sun, Jul 23, 2017 at 8:18 PM, Marc Nieper-Wißkirchen <xxxxxx@nieper-wisskirchen.de> wrote:
I just noticed that, in fact, both the R6RS and the R7RS version of let(rec)-syntax are backward-compatible with the R5RS, they are just not mutually compatible.

The body of an R5RS-let(rec)-syntax is not spliced into the surrounding context, and the R7RS retains this semantics making both compatible. R6RS, however, has splicing semantics.

In the R5RS, however, it says, however, that the <body> of a let(rec)-syntax should be a sequence of one or more expressions (while the R7RS allows the <body> to a sequence of definitions followed by one or more expressions).

In the absence of definitions, however, there is no semantic difference between splicing the body in the surrounding context or not. Thus the R6RS is as well backwards-compatible with the R5RS.


I'm assuming you're referring to the text in R5RS 4.3.1 stating that for let[rec]-syntax:

  [...] <body> should be a sequence of one or more expressions.

I think the explicit description of internal definitions in R5RS 5.2.2 makes it clear
that internal definitions are allowed.  If you want to argue that the text from 4.3.1
precludes extensions, then you must also apply the same reasoning to 4.2.2,
where for let[*,rec] it states:

  [...] <body> should be a sequence of one or more expressions.

and similarly in 4.1.4 describing lambdas:

  [...] <body> should be a sequence of one or more expressions.

This would be absurd, so we can only assume internal definitions are allowed
everywhere described in 5.2.2, and are required to be non-splicing.

So R6RS is incompatible with R5RS on this point, and R7RS is compatible
(revising the text to make it slightly clearer, but not in need of any errata
(apart from the existing errata #13)).

I think a SRFI for let[rec]-syntax/splicing would be a good idea.

--
Alex
 

--

Marc


Marc Nieper-Wißkirchen <xxxxxx@nieper-wisskirchen.de> schrieb am Sa., 22. Juli 2017 um 13:16 Uhr:
For R7RS-large we can look forward and add a let(rec)-syntax/splicing. 

There are some edge cases that might need specification, though:

(let ()
  (let-syntax/splicing ((foo (syntax-rules () ((foo) 'foo)))
    (define-syntax foo (syntax-rules () ((foo) 'bar)))
    (foo)))

Does this evaluate to foo, bar, or is it an error? 

If we want to be able express the (non-splicing) let(rec) in terns of let(rec)-splicing by using the simple transformation

(let(rec)-syntax <bindings> <body>) => (let () (let(rec)-syntax/splicing <bindings> <body>),

the snippet from above will have to evaluate to bar.

Now, consider the following example:

(let ()
  (let-syntax/splicing ()
    (define let-syntax/splicing #f)
    #f))

This must be possible if we want this snippet to behave as a non-splicing let-syntax. It would, however, be violation of 5.4 of the R7RS, where is says:

"Macros can expand into definitions in any context that
permits them. However, it is an error for a definition to
define an identifier whose binding has to be known in order 
to determine the meaning of the definition itself, or of
any preceding definition that belongs to the same group
of internal definitions. Similarly, it is an error for an internal 
definition to define an identifier whose binding has
to be known in order to determine the boundary between
the internal definitions and the expressions of the body it
belongs to."

So I would like to see clear semantics for let(rec)-syntax/splicing that is in accordance with the rest of the R7RS. Possibly, let(rec)-syntax (non-splicing) won't be implementable with let(rec)-syntax/splicing then, meaning that we actually have too different binding constructs neither of which is expressible in terms of the other.
 
--

Marc