为什么这种语法可以模式化这个“for”宏?

时间:2014-09-25 05:09:06

标签: macros scheme

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

>       (对于'(0 1 2 3 4)'         (打印i)         (换行))

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

我的问题是为什么符号'in can the symbol the symbol'为? 符号'in不是唯一带有'in?

的模式

2 个答案:

答案 0 :(得分:1)

在Racket文档中,at some point表示

  

使用模板代替与模式匹配的表单,除了模板中模式变量的每个实例都替换为宏的一部分使用匹配的模式变量。

这让我觉得'as符号被忽略了。事实上,这个

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

同样适用。

要获得所需的行为,请使用

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

然后

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

>  (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))

答案 1 :(得分:1)

不评估宏模式。特别是,'as 不是符号。它只是列表(quote as)。 ('as 评估符号,但它本身并不是符号。)因此,您的宏实际上与以下内容相同:

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

其中quoteas是可以匹配任何内容的模式变量。

正如uselpa的回答中所提到的,要求使用as的正确方法是使用文字列表:

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

或者,如果您真的很虐待,并希望让用户引用as,请执行以下操作:

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

(是的,您甚至可以将文字列表更改为'as而不是(quote as),但这只会使您的宏无法读取。不要这样做。: - p)