[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: How to use-modules within macro?
From: |
Mark H Weaver |
Subject: |
Re: How to use-modules within macro? |
Date: |
Thu, 29 Aug 2019 19:04:07 -0400 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/26.2 (gnu/linux) |
Hi Florian,
"pelzflorian (Florian Pelz)" <address@hidden> writes:
> I am writing a Guile macro to manipulate Scheme code and am stuck on
> what I hope is a simple problem and it would be nice if you could
> explain. I try:
>
> (define-syntax O
> (lambda (x)
> (syntax-case x ()
> ((_)
> #`(begin (use-modules (ice-9 local-eval))
> (local-eval 42 (the-environment)))))))
> (pk (O))
This approach is misguided and unnecessary. You don't need to include
'use-modules' in your macro expansion, and it's best avoided.
The references to 'local-eval' and 'the-environment' in the macro
template above will refer to bindings present in the module where 'O' is
defined, *not* the module where 'O' is used. This is part of what it
means to say that 'O' is a "hygienic" macro.
Therefore, all you need to do is make sure (ice-9 local-eval) is
imported in the module where 'O' is defined, like this:
--8<---------------cut here---------------start------------->8---
(define-module (my-module-that-exports-O)
#:use-module (ice-9 local-eval)
#:export (O))
(define-syntax O
(lambda (x)
(syntax-case x ()
((_)
#`(local-eval 42 (the-environment))))))
--8<---------------cut here---------------end--------------->8---
Does that work for you?
FYI, the way this works internally is that the macro expander operates
on "syntax objects" instead of plain S-expressions. The main difference
is that "syntax objects" keep additional information about the lexical
environments where the embedded identifiers were originally found. So
when a use of (O) expands into (local-eval 42 (the-environment)), the
identifiers 'local-eval' and 'the-environment' are looked up in the
proper environment.
By the way, another consequence of hygiene, which you probably don't
want here, is that the (the-environment) above will capture the lexical
environment where 'O' was *defined*, instead of the environment where
(O) is used. In other words, in (let ((x 5)) (O)), the captured lexical
environment will not include 'x'.
I should also mention that using (the-environment) will pretty much
disable most compiler optimizations that would otherwise occur with that
top-level form. That entire mechanism is best avoided if at all
possible.
Can you tell me more broadly what you are trying to accomplish here?
I may be able to suggest an alternate approach.
Best,
Mark