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 Jakub T. Jankiewicz 23 Jan 2024 19:46 UTC

Hi Wolfgang,

Thanks for the explanation, in fact I was confused because arg1 didn't appear
in the pattern but appear in expansion, didn't realized that it's was like
binding in let where the arg1 was the name of a variable. I was looking at
the pattern and expansion in isolation without looking at the other
nested pattern and expansion.

Now I understand how this macro works thanks to Jens Axel explanation.

I also now understand better the syntax-rules since the code doesn't work
correctly in my Scheme interpreter. My code is really naive it's simple
replacement of symbols with gensym, it works most of the time but not in this
case.

On Tue, 23 Jan 2024 14:17:43 -0500
Wolfgang Corcoran-Mathe <xxxxxx@sigwinch.xyz> wrote:

> 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.)
>

--
Jakub T. Jankiewicz, Senior Front-End Developer
https://jcubic.pl/me
https://lips.js.org
https://koduj.org