Source code Jakub T. Jankiewicz (23 Jan 2024 00:59 UTC)
Re: Source code Jens Axel Søgaard (23 Jan 2024 01:24 UTC)
Re: Source code Jens Axel Søgaard (23 Jan 2024 01:48 UTC)
Re: Source code Jakub T. Jankiewicz (23 Jan 2024 19:48 UTC)
Re: Source code Wolfgang Corcoran-Mathe (23 Jan 2024 19:17 UTC)
Re: Source code Jakub T. Jankiewicz (23 Jan 2024 19:46 UTC)
Re: Source code Wolfgang Corcoran-Mathe (23 Jan 2024 22:10 UTC)

Re: Source code Wolfgang Corcoran-Mathe 23 Jan 2024 19:17 UTC

Hi Jakub,

On 2024-01-23 01:58 +0100, Jakub T. Jankiewicz wrote:
> It looks like args1 in both macros is unbound. I'm not an expert in Scheme
> hygienic macros but I'm pretty comfortable with them, and it looks like an
> error. The macros did work, but I'm not sure if the code is correct. I'm also
> not sure if I fully understand how those macros work.

I was a little confused by what you meant by args1 being "unbound".
syntax-rules doesn't "bind" anything, so a syntax-rules clause like

    ((foo x) (bar x y))

is perfectly fine. The relevant part of the spec is the sentence:
"Identifiers that appear in the template but are not pattern variables
or the identifier <ellipsis> are inserted into the output as literal
identifiers." (R7RS 4.3.2) Without this rule, even the simplest of
macros would be impossible to write with syntax-rules.

I'm sure you know this already.

So, if I understand correctly, you're really asking why inserting
arg1 at each step doesn't result in shadowing. If syntax-rules
inserts non-pattern-variable identifiers literally, you'd expect to
get:

    (let-values (((proc) operator)
                 ((arg1) operand1)
                 ((arg1) operand2)  ; oops
                 ((arg1) operand3)
                 ...)
      ...)

This isn't what happens. What you actually get is something like:

    (let-values (((proc) operator)
                 ((arg1-1) operand1)
                 ((arg1-2) operand2)
                 ((arg1-3) operand3)
                 ...)
      ...)

Essentially, the arg1 identifier is hygienically renamed each time
it's inserted, so that all of the names are distinct from each other
and from other identifiers in the same context. We can be sure of this
because of the hygiene condition:

> Hygiene Condition for Macro Expansion
> Generated identifiers that become binding instances in
> the completely expanded program must only bind variables
> that are generated at the same expansion step.

(Kohlbecker et al, 1986, p. 4)

In essence, MNW is using hygienic expansion to implement something
like R6RS's generate-temporaries.

It may be slightly easier to follow in my R6RS fork of the sample
implementation, which doesn't use any syntax-rules extensions:
https://github.com/Zipheir/srfi-210/blob/master/srfi/210.scm

Regards,

Wolf

(MNW, et al: Please correct me if I'm missing details here.)

--
Wolfgang Corcoran-Mathe  <xxxxxx@sigwinch.xyz>