Trying to learn macros, have question on code snippet

Hello. I am new to Scheme/Racket (not to programming) and am trying to learn Racket through BeautifulRacket. After a few chapters I got interested in learning more about Racket's macro capabilities (before going back to the BR chapters) and ran off to read Greg Hendershott's "Fear of Macros". In it, in chapter 4 (4 Pattern matching: syntax-case and syntax-rules), he has this code (the idea is to provide a capability to "index" into a hash table using dot notation, I guess - such as (hash.refs js.a.b.c) should return "value"):

(define js (hasheq 'a (hasheq 'b (hasheq 'c "value"))))

(define/contract (hash-refs h ks [def #f])
  ((hash? (listof any/c)) (any/c) . ->* . any)
  (with-handlers ([exn:fail? (const (cond [(procedure? def) (def)]
                                          [else def]))])
    (for/fold ([h h])
              ([k (in-list ks)])
      (hash-ref h k))))

(define-syntax (hash.refs stx)
  (syntax-case stx ()
    ; If the optional ‘default' is missing, use #f.
    [(_ chain)
     #'(hash.refs chain #f)]
    [(_ chain default)
     (let* ([chain-str (symbol->string (syntax->datum #'chain))]
            [ids (for/list ([str (in-list (regexp-split #rx"\." chain-str))])
                   (format-id #'chain "~a" str))])
       (with-syntax ([hash-table (car ids)]
                     [keys (cdr ids)])
         #'(hash-refs hash-table 'keys default)))]))

What I am getting stuck on is -> why is "keys" (a list) in #'(hash-refs hash-table 'keys default)))])) quoted?

Thanks!

3 Likes

In (with-syntax ([keys (cdr ids)[) ...) the pattern keys is bound to a syntax object representing a list (the result of (cdr ids)).

Within the template that begins with #' the pattern variable keys will be replaced by the syntax object to which it is bound - that is, it will be replaced the the identifiers from (cdr ids).

1 Like

I think, IOW, that keys contains the equivalent of #'(a b c) (assuming the invocation was something like (hash.refs table a b c)). When putting this list in, without a quote, it would expand to (hash-refs table (a b c) #f). This is unlikely to be correct; what we really want is (hash.refs table '(a b c) #f).

With syntax-parse this kind of example is a bit clearer, but Fear of Macros does a nice job connecting the dots between low-level macro primitives and higher-level DSLs like syntax-case/syntax-parse.

2 Likes

I guess what has/had me confused is that in the same code, one line above "hash-table" is the first element of "ids" and I guess that's a syntax object as well, yet it is not quoted in the #'(hash-refs hash-table 'keys default) line. I got a bit confused, new to this. Thanks :slight_smile:

1 Like

Yep, that makes perfect sense to me. Thanks :slight_smile:

1 Like