unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
From: Frank Terbeck <ft@bewatermyfriend.org>
To: Maxime Devos <maximedevos@telenet.be>
Cc: guile-devel@gnu.org
Subject: Re: Recursive Macros generating Definitions
Date: Mon, 03 Oct 2022 15:41:04 +0200	[thread overview]
Message-ID: <87lepxkosv.fsf@ft.bewatermyfriend.org> (raw)
In-Reply-To: <939c81ae-5b12-1910-5fbd-8ad99a697da6@telenet.be> (Maxime Devos's message of "Mon, 3 Oct 2022 14:48:39 +0200")

Hey Maxime!

Maxime Devos wrote:
> On 03-10-2022 13:32, Frank Terbeck wrote:
>> When looking at  this, I also saw the following,  which might be related
>> if ‘syntax-rules’ is implemented using  ‘syntax-case’
>
> It is, IIRC.
>
>> (I didn't check if
>> this is the case):
>>      (define-syntax-rule (foobar n) (define quux n))
>>      ,exp (foobar 23)
>>    → (define quux-ea7bdcf8675f4a4 23)
>
> This is correct (as in, functioning as intended and not a bug) to my
> understanding -- in the match expression of 'foobar', 'quux' does not appear,
> so the for hygiene, the 'quux' inside shouldn't be the quux outside.
[…]
> It's sometimes a bit inconvenient -- sometimes you _want_ to define 'quux' (and
> not just only available to the macro), but that's easily resolved by adding an
> additional 'quux' argument to 'foobar':
>
>       (define-syntax-rule (foobar quux n) (define quux n))
>       ,exp (foobar quux 23)

I get the point, but I think it's sort of surprising, when everything in
the macro-language is  otherwise quite literal, to  my understanding. It
may be warranted to  point this out in the documentation  that this is a
side effect of hygienic macros, I think.


>> (define-syntax generate-shorthands [...]
>
> Your recursive macro is, well, recursive.  This is fine, but IIUC a consequence
> of this is that the recursive 'call' to generate-shorthands is a new lexical
> lexical environment (hence, hygience, so -?????? stuff).
>
> As such, I consider this not a bug in Guile, but a bug in your code.
>
> My proposal would be to change the 'x' in (datum->syntax x) -- instead of using
> #'x (which refers to the whole expression, which in a recursive call has an
> undesired lexical environment), use something of the 'end-user' of
> generate-shorthands, say, #'s (i.e., SEMANTICS-SYMBOL) (for the right lexical
> environment).
>
> If I make that change, I get some reasonable output (no -????? suffixes):
>
> $1 = (begin
>   (define (varint:sint32-decode bv)
>     (varint-decode bv 32 zig-zag))
>   (define (varint:sint32-encode n)
>     (varint-encode n 32 zig-zag)))

Thanks, this does work indeed!

So,   clearly  I   don't  fully   understand  the   first  argument   to
‘datum->syntax’, because  I thought ‘x’  would be exactly right  since I
thought it  captured the context  of where the  macro was called  in the
original  code.  But  every  time,  I  perform  an  indirection  through
recursion, the context captured by ‘x’ is bound to something new, that's
in the context of the outer level of macro expansion.

If I understand this correctly, using #'s here, refers to something that
was created  at the source level  of where the initial  expansion of the
macro happened.  If that  is the  case, is it  correct, that  it doesn't
really matter whether I used #'s or #'w. And that seems to be the case.

And if I wanted to do this:

  ((op s w)
   (let ((base (make-base-name #'s #'w)))
     (with-syntax ((enc (datum->syntax #'op (symbol-append base '-encode)))
                   (dec (datum->syntax #'op (symbol-append base '-decode))))
       #'(begin (define (dec bv) (varint-decode bv w s))
                (define (enc  n) (varint-encode  n w s))))))

…I'd still  end up with  the -HEX amended  symbol names, because  in the
recursing cases, I am using  a literal ‘generate-shorthands’ symbol. But
if I'd do this:

  ((op (sems ...) (widths ...)) #'(begin (op sems (widths ...)) ...))
  ((op sem        (widths ...)) #'(begin (op sem widths) ...))

It should work, because ‘op’ always  refers to the syntactic object used
at the source level, where the user  used the macro, which means that in
the base-case, the  ‘op’ template variable still refers  to the original
source position,  so the scopes match  up correctly, so that  the intro-
duced bindings don't have to be amended for hygiene.

In hindsight, I should have sent this to -users after all. :)

This behaviour  is probably  explained in one  of the  ‘syntax-case’ and
‘datum->syntax’ examples  in the manual,  but it  wasn't clear to  me at
all. Not sure how, but I think there's room for improvement here. :)

Thanks for  clearing this up!  And feel free  to correct anything  I got
wrong in what I wrote in the above.


Regards, Frank



  reply	other threads:[~2022-10-03 13:41 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-03 11:32 Recursive Macros generating Definitions Frank Terbeck
2022-10-03 12:48 ` Maxime Devos
2022-10-03 13:41   ` Frank Terbeck [this message]
2022-10-03 18:42     ` Jean Abou Samra
2022-10-03 20:29       ` Frank Terbeck

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87lepxkosv.fsf@ft.bewatermyfriend.org \
    --to=ft@bewatermyfriend.org \
    --cc=guile-devel@gnu.org \
    --cc=maximedevos@telenet.be \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).