Macros Scheme宏-在转换中成对,但作为输出列出?

Macros Scheme宏-在转换中成对,但作为输出列出?,macros,scheme,Macros,Scheme,假设我在R5RS方案中有以下宏: (define-syntax pair-test (syntax-rules () ((_ (a b . c)) (quote (a b . c))))) 宏将输入对转换为输出对,正如预期的那样: (pair-test (1 2 . 3)) ==> (1 2 . 3) 我也可以按照规范的允许将列表传递给宏。但是,输出是列表而不是成对的: (pair-test (1 2 3)) ==> (1 2 3) 这到底是怎么回事?

假设我在R5RS方案中有以下宏:

(define-syntax pair-test
  (syntax-rules ()
     ((_ (a b . c))
      (quote (a b . c)))))
宏将输入对转换为输出对,正如预期的那样:

(pair-test (1 2 . 3))
==> (1 2 . 3)
我也可以按照规范的允许将列表传递给宏。但是,输出是列表而不是成对的:

(pair-test (1 2 3))
==> (1 2 3)

这到底是怎么回事?为什么输出是一个列表而不是一对?

在第二种情况下,
c
可能是
(3)()
?我不确定,但这对我来说是有意义的。然后引用
(ab.c)
将是
(12.(3)()
,这是
(12.(3))
(3)
是一个合适的列表,所以
(12.3)

要了解这里发生了什么,您需要知道Scheme中的列表是一个由成对元素和其他列表组成的递归链。任何遵循列表形式的数据都将始终作为列表打印。一旦知道基本列表是如何构造的,就可以看到宏中发生了什么

可以使用
操作符或使用
cons
功能创建方案中的对。以下是一对简单的数字:

(quote (1 . 2))
==> '(1 . 2)
(cons 1 2)
==> '(1 . 2)
要在Scheme中创建1的列表,可以将某物与空列表配对:

(quote (1 . ()))
==> '(1)
(cons 1 (list))
==> '(1)
2的列表左边是一对某物,右边是1的列表。同样,3的列表是一个元素与2的列表配对:

(quote (1 . (2 . (3 . ()))))
==> '(1 2 3)
(cons 1 (cons 2 (cons 3 (list))))
==> '(1 2 3)
要查看宏正在执行的操作,可以重新排列
(引号(ab.c))
,使其更加明确:

(quote (a . (b . c)))
(cons (quote a) (cons (quote b) (quote c)))
现在您可以看到,此表单与构建列表时非常相似。如果
(引号c)
生成一个列表,那么整个表达式将是一个列表。在
(成对测试(1 2 3))
的情况下,
c
变为
(3)()

REPL将此值打印为列表,因为它是“正确的列表”。每个右侧(
cdr
)都是一个列表,一直到最后的空列表,因此该值完全遵循列表形式。REPL假定您希望将结果显示为列表,因此打印时不显示

您将看到
(12.3)
(配对测试(12.3)),因为这就是REPL打印“不正确列表”的方式。如果配对链中的最后一个元素不是空列表,则该值被视为“不正确列表”,并将以不同方式打印:

(quote (1 . (2 . 3)))
==> '(1 2 . 3)
(cons 1 (cons 2 3))
==> '(1 2 . 3)
对事实上,c是
(3.()
——你不应该有额外的引号——但你基本上是对的。
(quote (1 . (2 . 3)))
==> '(1 2 . 3)
(cons 1 (cons 2 3))
==> '(1 2 . 3)