[racket] Wildcard Macro Names?

From: Eli Barzilay (eli at barzilay.org)
Date: Sun Jan 27 04:08:05 EST 2013

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!


Posted on the users mailing list.