Your `syntax-rules` macro-defined macro uses the name "b", but that name is 
already bound by the `syntax-case` step of `define-primitive`. So your 
expansion looks like this:

(define-primitive (add a b c d) (print (+ a b c d)))


  (define add-property-table (make-hash))
  (hash-set! add-property-table 'is-prime #t)
  (hash-set! add-property-table 'arg-count (length '(a b c d)))
  (hash-set! add-property-table 'emitter (lambda (a b c d) (print (+ a b c d)))
  (define-syntax add
    (syntax-rules ()
      ((add a) (list 'add a))
      ((add a (print (+ a b c d))) (list 'add a (print (+ a b c d)))))))

Note that `add` macro you create uses `(print (+ a b c d))` instead of `b` in 
the second pattern. You can rectify this by using a different name.

However, here are a couple other notes to consider:

- `syntax-case` is considered somewhat obsolete in the Racket community, 
`syntax-parse` allows for better-specified patterns and error messages. Your 
example with syntax parse would look like (synatx-parse stx [(_ (primitive-name 
arg*:id ...) b:expr ...+) <macro body here>]). This makes your macro throw a 
syntax error if anything used for `arg*` isn't an identifier, or if 
non-expression syntax (like a keyword) is used for `b`.
- Construction of the "-property-table" identifier can be done much more 
concisely with `format-id`, making your DS/SS/SD shorthands unnecessary
- Avoid mutable data structures unless you know you need mutation. Your 
`hash-set!` code can be easily expressed with a plain call to `hash`:

(define table-name
  (hash 'is-prime #t
        'arg-count (length '(a b c d))
        'emitter (lambda (a b c d) (print (+ a b c d)))))

- When a macro defines a macro, the elipses (...) refer to the outer macro 
template. This is why you couldn't use ... in the `syntax-rules` macro you 
attempted to create. You can get around this by using two ellipses grouped 
together, like this:

(define-syntax primitive-name
  (syntax-rules ()
    ((primitive-name a (... ...)) (list 'primitive-name a (... ...)))))

- It's considered good Racket style to use brackets for the clauses of 
`syntax-rules` / `syntax-case` / `syntax-parse`, like this:

(syntax-case stx ()
  [(pattern ...) body ...]
  [(pattern ...) body ...]))

- If you (require syntax/parse/define) you can use `define-simple-macro` (badly 
named, we know) in place of `define-syntax-rule`. They function similarly, but 
the former uses `syntax/parse` and thus lets you specify constraints like "this 
should be an identifier".
- The macro you create for each primitive is exactly the same. It may be 
simpler to factor that out into a separate macro:

(define-simple-macro (define-primitive-application-syntax (primitive-name:id 
arg:id ...))
  (define-simple-macro (primitive-name arg-expr:expr (... ...))
    (list 'primitive-name arg-expr ...)))

(define-syntax (define-primitive stx)
  (syntax-parse stx ()
    [(_ (primitive-name:id arg:id ...) body ...+)
     #:with table-name
            (format-id #'primitive-name "~a-property-table" #'primitive-name)
        (define table-name <hash-expr-mentioned-previously>)
        (define-primitive-application-syntax (primitive-name arg ...))]))

Hope this helps!

You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
For more options, visit

Reply via email to