12

I'd like to create a syntactic form in Racket that can accept a keyword argument, the way some functions can.

Having reduced it to a simple example, I tried writing:

(define-syntax sum-of-products
  (syntax-rules (#:extra)
    [(sum-of-products ([a b] ...))
     (+ (* a b) ...)]
    [(sum-of-products ([a b] ...) #:extra extra)
     (+ extra (* a b) ...)]))

Such that the following would then work:

(sum-of-products ([2 2] [3 3])) → 13
(sum-of-products ([2 2] [3 3]) #:extra 5) → 18

Unfortunately, Racket calls this "bad syntax", so obviously that attempt wasn't correct.

Can this be done?

Taymon
  • 24,950
  • 9
  • 62
  • 84

1 Answers1

15

Keywords in syntactic patterns are treated the same as literals like numbers etc, so you don't need to specify them as keywords. (That's needed only for identifiers.) So the following works (note that I fixed the typo you had in the second example):

#lang racket
(define-syntax sum-of-products
  (syntax-rules ()
    [(sum-of-products ([a b] ...))
     (+ (* a b) ...)]
    [(sum-of-products ([a b] ...) #:extra extra)
     (+ extra (* a b) ...)]))
(sum-of-products ([2 2] [3 3]))
(sum-of-products ([2 2] [3 3]) #:extra 5)

See also syntax-parse for a utility that can make parsing keywords easier.

Eli Barzilay
  • 29,301
  • 3
  • 67
  • 110
  • 5
    In particular, the `syntax-parse` documentation has a whole [section](http://docs.racket-lang.org/syntax/Optional_Keyword_Arguments.html) on writing macros with keyword arguments. – Sam Tobin-Hochstadt Apr 10 '12 at 18:51