[racket] Wildcard Macro Names?
On Wednesday, Scott Klarenbach wrote:
> Is it possible to have a macro bound to an identifier with wildcards
> in it?
>
> So, for example, a macro (@*) that would be used for (@x) and (@y),
> where the symbols x and y are available during expansion.
>
> Or is this something that would have to be done at the reader level?
> ie, (@ ...) is the macro, and the reader turns @x and @y into (@ x)
> and (@ y) respectively.
This is possibly irrelevant, but since there were some pointers in a
direction that is not doing the above:
1. You should try to avoid doing this at the reader level as much as
possible. If you're trying to replace `@foo' by something else,
then you can easily run into a mess when these things are quoted
etc. In addition, since you're at the reader level, you cannot
know if you're looking at something which is any other kind of
non-expression, like argument names etc.
(This is from experience: a previous attempt at the scribble reader
was reading @foo{blah} as (dispatch foo "blah"). It was
problematic for these reasons.)
2. Identifier macros don't seem so helpful either, since they're used
as bindings for known names.
3. Using `#%top' might work, if you want the bindings of the
wildcard-ed @foo identifiers to be values as in Danny's example,
but it won't work if you want them to be macros.
So if you really want them to be macros, then I think that your best
bet is to hook into both the `#%top' and the `#%app' macros, the
former to identify cases where you want (.... @foo ....) to expand to
some (.... "at-foo" ....), and the latter to identify cases where you
want (@foo ....) to get expanded to something else (that is, not just
expand the @foo as in the identifier case).
Here's an example that shows how both are used -- for fun, I made two
things magical, `foo%' identifiers, and `@foo' things that were read
by the scribble reader (which can be identified via a syntax
property).
-------------------------------------------------------------------------------
#lang at-exp racket/base
(module magic racket/base
(provide (rename-out [top #%top] [app #%app]))
(require (for-syntax racket/base))
(define-for-syntax (magical? id)
(and (identifier? id)
(regexp-match? #rx"%$" (symbol->string (syntax-e id)))))
(define-syntax (top stx)
(syntax-case stx ()
[(_ . id)
(cond [(magical? #'id) #''id]
[(syntax-property stx 'scribble) #''id]
[else #'id])]))
(define-syntax (app stx)
(syntax-case stx ()
[(_ id x ...)
(cond [(magical? #'id) #'(vector 'id x ...)]
[(syntax-property stx 'scribble) #'(list 'id x ...)]
[else #'(id x ...)])]))
)
(require 'magic)
blah%
(blah% 1 2 3)
@blah
@blah{zzz}
-------------------------------------------------------------------------------
--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://barzilay.org/ Maze is Life!