scheme 具有语法规则的方案透明和引用透明宏

示例

与其他主流编程语言相比,LISP和Scheme的最大优势是它们的宏系统。与C预处理器和其他宏语言不同,Scheme宏将已解析的代码作为输入,并返回扩展的代码作为输出。这是Scheme的“代码就是数据”短语的应用之一,正是这使得该语言如此强大。

Scheme中的宏是使用创建的define-syntax,可以通过多种方式定义宏。最简单的方法是使用syntax-rules,它使用模式匹配将输入代码转换为输出代码。

这个例子创建一个简单的for item in list和for list as item用于遍历列表中元素的语法:

(define-syntax for
  (syntax-rules (in as) ; 'in' and 'as' keywords must match in the pattern
    ; When the 'for' macro is called, try matching this pattern
    ((for element in list
          body ...) ; Match one or more body expressions
     ; Transform the input code
     (for-each (lambda (element)
                 body ...)
               list))
    ; Try matching another pattern if the first fails
    ((for list as element
          body ...)
     ; Use the existing macro for the transform
     (for element in list
          body ...))))

然后可以使用以下两个宏,以提供更强制的样式:

(let ((names '(Alice Bob Eve)))
  (for name in names
    (display "Hello ")
    (display name)
    (newline))
  (for names as name
    (display "name: ")
    (display name)
    (newline)))

运行代码将提供预期的输出:

Hello Alice
Hello Bob
Hello Eve
name: Alice
name: Bob
name: Eve

要查找的最常见错误是没有将正确的值传递给宏,这通常会导致无用的错误消息,该错误消息适用于扩展形式而不是宏调用。

for上面的语法定义不会检查是否传递了标识符和列表,因此传递任何其他类型将导致指向该for-each调用而不是该for调用的错误。调试它会破坏宏的用途,因此用户应将检查放在其中并报告使用错误,然后可以在编译时捕获该错误。