greghendershott / fear-of-macros

A practical guide to Racket macros
251 stars 27 forks source link

Fix `stx` args in section 4.1 #6

Closed greghendershott closed 6 years ago

greghendershott commented 11 years ago

Examples using datum->syntax and format-id in section 4.1 work when the macro is used directly, but don't work when the macro is used by another macro.

From IRC chat:

Re http://paste.lisp.org/display/139228 the tl;dr seems to be that this line is wrong:

    (with-syntax ([hyphen-datum (datum->syntax stx hyphen-symbol)])

Instead change stx to body0:

    (with-syntax ([hyphen-datum (datum->syntax body0 hyphen-symbol)])

That way, when the macro is used by another macro, the correct lexical scope is being used. So it looks like I need to:

  1. Change that example in Fear of Macros.
  2. Make sure I can explain clearly why this matters (hint: see http://jeapostrophe.github.io/2013-07-22-123list-post.html).
  3. Probably start a section like "Macro-Generating Macros".

The code from pastebin:

#lang racket

(require (for-syntax racket/syntax
                     racket/string))

(define-syntax (hyph stx)
  (syntax-case stx ()
    [(_ (names ...) (args ...)
        body0
        body ...)
     (let* ([syntax-list (syntax->list #'(names ...))]
            [symbol-list (map syntax-e syntax-list)]
            [string-list (map symbol->string symbol-list)]
            [hyphen-string (string-join string-list "-")]
            [hyphen-symbol (string->symbol hyphen-string)])
       (with-syntax ([hyphen-datum (datum->syntax stx hyphen-symbol)]) ;; <-- CHANGE THIS
         #'(define (hyphen-datum args ...)
             body0
             body ...)))]))

(define-syntax (get/set stx)
  (syntax-case stx ()
    [(_ field-name init-value)
     #'(begin
         (define field-name init-value)
         (hyph (set field-name) (value)
               (set! field-name value))
         (hyph (get field-name) ()
               field-name))]))

(get/set gogo "dancer")
(get-gogo)
(set-gogo "all clear")
(get-gogo) 
=>

4-sandbox.rkt:32:1: get-gogo: unbound identifier in module
  in: get-gogo
greghendershott commented 6 years ago

Closed in commit 53f5c9e; issue #25 is really the same as this.

greghendershott commented 6 years ago

Reopening: Although the concept is similar, I only updated uses of format-id, not the code mentioned in this issue.