简体   繁体   中英

why this syntax can pattern this “for” macro?

#lang racket
(define-syntax for
  (syntax-rules ()
    ((_ list 'as element body ...)
     (map (lambda (element)
            body ...)
          list))))

> (for '(0 1 2 3 4) 'in i (print i) (newline))

=> 0 1 2 3 4 '(# # # # #)

My question is why the symbol 'in can pattern the symbol 'as ? The symbol 'in isn't a only pattern with 'in?

In the Racket doc, at some point it says

The template is used in place of a form that matches the pattern, except that each instance of a pattern variable in the template is replaced with the part of the macro use the pattern variable matched.

which makes me think that the 'as symbol is simply ignored. And indeed, this

(define-syntax for
  (syntax-rules ()
    ((_ list element body ...)
     (map (lambda (element)
            body ...)
          list))))
(for '(0 1 2 3 4) i (print i) (newline))

works just as well.

To get the behaviour you want, use

(define-syntax for
  (syntax-rules (as)
    ((_ list as element body ...)
     (map (lambda (element)
            body ...)
          list))))

then

>  (for '(0 1 2 3 4) as i (print i) (newline))
0
1
2
3
4
'(#<void> #<void> #<void> #<void> #<void>)

but

>  (for '(0 1 2 3 4) in i (print i) (newline))    
for: bad syntax in: (for (quote (0 1 2 3 4)) in i (print i) (newline))

Macro patterns are not evaluated. In particular, 'as is not a symbol. It is simply the list (quote as) . ( 'as evaluates to a symbol, but it isn't by itself a symbol.) Thus, your macro is really the same as:

(define-syntax for
  (syntax-rules ()
    ((_ list (quote as) element body ...)
     (map (lambda (element)
            body ...)
          list))))

where quote and as are pattern variables that can match anything whatsoever.

As mentioned in uselpa's answer, the correct way to require the use of as exactly as written is to use the literal list:

(define-syntax for
  (syntax-rules (as)
    ((_ list as element body ...)
     (map (lambda (element)
            body ...)
          list))))

Or, if you're really sadistic and want to make the user quote the as , do this:

(define-syntax for
  (syntax-rules (quote as)
    ((_ list 'as element body ...)
     (map (lambda (element)
            body ...)
          list))))

(Yes, you can even change the literal list to be 'as instead of (quote as) as I have it, but that just makes your macro unreadable. Don't do that. :-P)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM