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:48 UTC

Thanks for the explanation, now I understand. I was looking at the pattern
and expansion in isolation. Didn't realized that arg1 was a binding in
let-values at full expansion.

On Tue, 23 Jan 2024 02:48:26 +0100
Jens Axel Søgaard <xxxxxx@soegaard.net> wrote:

> Oh! I forgot about the `args1` in the next clause:
>
>     ((aux %consumer (%producer1 producer2 :::) (temp :::))
>      (aux %consumer (producer2 :::) (temp ::: (%producer1 args1))))
>
> Here the `args1` appears only in the template. This means that the
> identifier `args1`
> is (hygienically) introduced here. We see that the template consists of
> a call to `aux`. The identifier `args1` will end up as a variable name
> in the `let-values` form.
>
> The round about way the macro is defined, introduces one `args1` per
> producer
> present in the original macro call. Since each `args1` is introduced in
> its own call to `aux` they will get different scopes. That is,
> the `let-values` expression will not complain about duplicate identifiers
> in the binding clauses.
>
> /Jens Axel Søgaard
>
>
> Den tirs. 23. jan. 2024 kl. 02.24 skrev Jens Axel Søgaard <
> xxxxxx@soegaard.net>:
>
> > Hi,
> >
> > Here is the `call/mv` macro:
> >
> > (define-syntax call/mv
> >   (syntax-rules ()
> >     ((call/mv consumer producer1 ...)
> >      (letrec-syntax
> >          ((aux (syntax-rules ::: ()
> >                  ((aux %consumer () ((%producer1 args1) :::))
> >
> >                   (let-values (((proc) %consumer)
> >                                (args1 %producer1) :::)
> >                     (apply proc (append args1 :::))))
> >                  ((aux %consumer (%producer1 producer2 :::) (temp :::))
> >                   (aux %consumer (producer2 :::) (temp ::: (%producer1
> > args1)))))))
> >        (aux consumer (producer1 ...) ())))))
> >
> > We are dealing with a macro `call/mv` that expands into a `letrec-syntax`
> > form,
> > which defines a local macro `aux`.
> >
> > From
> >          ((aux (syntax-rules ::: ()
> >
> > we see that `:::` will be used as an ellipsis in both the pattern and
> > template of the aux-macro.
> >
> > The pattern is `(aux %consumer () ((%producer1 args1) :::))`
> > and the template is `(let-values ...)`.
> >
> > We see now that `args1` appears in the pattern - and thus `args1`
> > is bound as a pattern variable in the template that follows.
> >
> > /Jens Axel Søgaard
> >
> > Den tirs. 23. jan. 2024 kl. 01.59 skrev Jakub T. Jankiewicz <
> > xxxxxx@onet.pl>:
> >
> >> Hi,
> >>
> >> I have a question about the provided implementation:
> >>
> >> (define-syntax apply/mv
> >>   (syntax-rules ()
> >>     ((apply/mv operator operand1 ... producer)
> >>      (letrec-syntax
> >>          ((aux (syntax-rules ::: ()
> >>                  ((aux %operator () ((%operand1 arg1) :::) %producer)
> >>                   (let-values (((proc) %operator)
> >>                                ((arg1) %operand1) :::
> >>                                (args %producer))
> >>                     (apply proc arg1 ::: args)))
> >>                  ((aux %operator (%operand1 operand2 :::)
> >>                                  (temp :::) %producer)
> >>                   ;; args1 is not defined
> >>                   (aux %operator (operand2 :::) (temp ::: (%operand1
> >> arg1))
> >>                        %producer)))))
> >>        (aux operator (operand1 ...) () producer)))))
> >>
> >> (define-syntax call/mv
> >>   (syntax-rules ()
> >>     ((call/mv consumer producer1 ...)
> >>      (letrec-syntax
> >>          ((aux (syntax-rules ::: ()
> >>                  ((aux %consumer () ((%producer1 args1) :::))
> >>                   (let-values (((proc) %consumer)
> >>                                (args1 %producer1) :::)
> >>                     (apply proc (append args1 :::))))
> >>                  ((aux %consumer (%producer1 producer2 :::) (temp :::))
> >>                   (aux %consumer (producer2 :::)
> >>                                  ;; args1 is not defined
> >>                                  (temp ::: (%producer1 args1)))))))
> >>                                  (aux consumer (producer1 ...) ())))))
> >>
> >>
> >> 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.
> >>
> >> Where the args1 name (from last nested syntax) come from?
> >>
> >> The same happen with set!-values macro but with temp1 symbol:
> >>
> >> (define-syntax set!-values
> >>   (syntax-rules ()
> >>     ((set!-values (var1 ...) producer)
> >>      (letrec-syntax
> >>          ((aux (syntax-rules ::: ()
> >>                  ((aux () ((%var1 temp1) :::) %producer)
> >>                   (let-values (((temp1 ::: . temp*) %producer))
> >>                     (set! %var1 temp1) :::))
> >>                  ((aux (%var1 var2 :::) (temp :::) %producer)
> >>                   ;; temp1 is not defined here
> >>                   (aux (var2 :::) (temp ::: (%var1 temp1)) %producer)))))
> >>        (aux (var1 ... ) () producer)))
> >>     ((set!-values (var1 ... . var*) producer)
> >>      (letrec-syntax
> >>          ((aux (syntax-rules ::: ()
> >>                  ((aux () ((%var1 temp1) ::: (%var* temp*)) %producer)
> >>                   (let-values (((temp1 ::: . temp*) %producer))
> >>                     (set! %var1 temp1) :::
> >>                     (set! %var* temp*)))
> >>                  ((aux (%var1 var2 :::) (temp :::) %producer)
> >>                   ;; temp1 is not defined here
> >>                   (aux (var2 :::) (temp ::: (%var1 temp1)) %producer)))))
> >>        (aux (var1 ... var*) () producer)))
> >>     ((set!-values var* producer)
> >>      (let-values ((temp*) producer)
> >>        (set! var* temp*)))))
> >>
> >> I hope that this is not something that yet to learn about Hygienic
> >> macros.
> >>
> >> --
> >> Jakub T. Jankiewicz, Senior Front-End Developer
> >> https://jcubic.pl/me
> >> https://lips.js.org
> >> https://koduj.org
> >>
> >
> >
> > --
> > --
> > Jens Axel Søgaard
> >
> >
>

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