GNU bug report logs -
#76132
Clojure-style auto-gensyms for macros
Previous Next
Reported by: Tassilo Horn <tsdh <at> gnu.org>
Date: Fri, 7 Feb 2025 21:13:02 UTC
Severity: wishlist
Tags: patch
Done: Tassilo Horn <tsdh <at> gnu.org>
Bug is archived. No further changes may be made.
Full log
Message #50 received at 76132 <at> debbugs.gnu.org (full text, mbox):
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:
Hi Stefan,
>> Why?
>
> I'd ask the author of the code.
;-)
>> I would expect that it's one set of uninterned symbols per expansion.
>
> Try:
>
> (defmacro my-foo (exp)
> (with-uninterned-symbols
> `(let ((x$ 6))
> (+ x$ ,exp))))
>
> and then check (equal (macroexpand '(my-foo r)) (macroexpand '(my-foo r)))
That's shocking! :-|
> [ Admittedly, this all depends on when `with-uninterned-symbols` is
> macro-expanded, but in most cases it will be macro-expanded once and
> for all when the macro is defined. ]
Well, my naive assumption about macro expansion is that it's done lazily
from inside-out. In that case, I would assume the macro works as I
intended. Also nesting should be no problem, because when the outer
with-uninterned-symbols is expanded, any inner with-uninterned-symbols
has already been expanded so its own xs $ have been replaced with #:xs.
I guess you are talking about eager macro expansion, right? I have no
clue how that works and the docs don't tell either. Does it mean the
macro is expanded once its defmacro form is reached and the resulting
code is just inserted at its usages? But if that's the case, how are
the macro arguments injected in the code at the right places?
And furthermore, why does
(defmacro th/my-foo (exp)
(let ((x (make-symbol "x")))
`(let ((,x 6))
(+ ,x ,exp))))
not exhibit the exactly same problem? I guess it's because "the
machine" knows that every ,foo needs to be once-per-expansion, right?
Or maybe this dependency disables eager macro expansion for this macro
altoghether?
Is there a way to fix my macro? Maybe to define it so that it would
result in something like
(let-alist (collect-$-vars exp)
;; Now build a replacement for exp which uses ,.x accesses in place
;; of x$, e.g., this:
`(let ((,.x 6))
(+ ,.x ,exp)))
such that there's a "dependency" of the expansion to an expression
that's evaluated at expansion time which in turn depends on exp?
>> Oh, and obviously you made me curious about those weird corner cases.
>> Please elaborate! ;-)
>
> I wish I could. I'm starting to wonder if I dreamed it.
> The best I could come up with is:
>
> (defmacro my-countref-let (var form &rest body)
> (with-uninterned-symbols
> `(let ((x$ ,form)
> (count$ 0))
> (cl-symbol-macrolet ((,var (progn (cl-incf count$) x$)))
> (unwind-protect
> (progn ,@body)
> (message "%S ref'd %d times" ',var count$))))))
>
> where (my-countref-let v1 67 (my-countref-let v2 89 (+ v1 v2))) will
> say that `v2` was referenced twice and `v1` zero times (at least if
> that macro is byte-compiled).
Jesus Christ! ;-)
Bye,
Tassilo
This bug report was last modified 147 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.