I'm working with the Racket macro extension syntax-id-rules
, that some other Scheme implementations provide under the name identifier-syntax
. These let you specify macro expansions that will happen even when the defined identifier isn't in head position. So for example:
(define hidden #f)
(define-syntax proxy
(syntax-id-rules (set!)
[(set! proxy v) (set! hidden v)]
[proxy hidden]))
will set up the identifier proxy
to be a proxy for hidden
. This is a useless example, but it illustrates the usage.
I find myself in a situation where I want a global ordinary macro, let's call it foo
, that I want to override in some cases where I'm using an identifier macro like proxy
. That is, I want to be able to do something like this:
(define-syntax foo
(syntax-rules ()
[(foo arg ...) 'default]))
(define hidden #f)
(define-syntax proxy
(syntax-id-rules (foo set!)
[(foo proxy arg ...) 'special]
[(set! proxy v) (set! hidden v)]
[proxy hidden]))
(foo proxy) ; should return 'special
But in fact the last line returns 'default
, because the foo
macro gets expanded before the proxy
one.
Any ideas how I might achieve something along these lines, but with the proxy
identifier macro overriding the default macro definition for foo
? I'm not committed to the above architecture specifically.
Added: This isn't for any real-world usage, but part of a demonstration of a theoretical point in formal semantics.
@soegaard explained it perfectly. You can't do what you want directly without modifying the macro expander.
To extend @soegaard's answer, here is a way to simulate what you are asking for. It essentially does a "double-dispatch" macro expansion. As soegaard noted though, there's probably a more idiomatic way to achieve what you want, depending on your goals.
It seems to me that you need to find an alternative strategy. Maybe we can find a solution if you provide more details of the situation you want to use this in.
Anyways, here is why your strategy don't work. When you write
you associate a syntax-transformer with the identifier
proxy
. That transformer is called by the expander when it sees either(proxy ...)
,(set! proxy ...)
, orproxy
.In order to control what
(foo proxy arg ...)
expands to you need to specify it in the syntax-transformer associated withfoo
.Now depending on the situation there might be tricks that can be played.
For example one could imagine wrapping your program in a new form, that rewrites
(foo proxy arg ...)
into(proxy 'was-a-foo-originally arg ...)
and then let the syntax-transformer forproxy
handle the rest.The easy solution is to move the handling of
(foo proxy arg ...)
into the transformer forfoo
, but you specifically ask for a solution wherefoo
isn't changed.