假设我在R 5 RS方案中有以下宏:
(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)
这到底发生了什么?为什么输出是一个列表而不是一对?
答案 0 :(得分:5)
第二种情况可以c
成为(3 . ())
吗?我不是积极的,但这对我有意义。然后引用(a b . c)
为(1 2 . (3 . ()))
,(1 2 . (3))
且(3)
是正确的列表,所以(1 2 3)
?
答案 1 :(得分:2)
要了解这里发生了什么,您需要知道Scheme中的列表是一对元素和其他列表的递归链。任何遵循列表形式的数据将始终作为列表打印。一旦你知道如何构建基本列表,你就能看到宏中发生了什么。
可以使用.
运算符或使用cons
函数创建Scheme中的对。这是一对简单的数字:
(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)
要了解您的宏正在做什么,您可以重新安排(quote (a b . c))
更明确:
(quote (a . (b . c)))
(cons (quote a) (cons (quote b) (quote c)))
现在您可以看到此表单与构建列表时非常相似。如果(quote c)
导致列表,那么整个表达式将是一个列表。在(pair-test (1 2 3))
的情况下,c
变为(3 . ())
:
(quote (a . (b . c)))
==> (quote (1 . (2 . (3 . ()))))
==> '(1 2 3)
(cons (quote a) (cons (quote b) (quote c)))
==> (cons '1 (cons '2 '(3 . ())))
==> '(1 2 3)
这个值由REPL作为列表打印,因为它是一个“正确的列表”。每个右侧(cdr
)都是一个列表,一直到最后的空列表,所以这个值完全遵循列表形式。 REPL假定您希望将结果看作列表,因此在没有.
的情况下打印出来。
您会看到'(1 2 . 3)
(pair-test (1 2 . 3))
,因为这是REPL打印“不正确的列表”的方式。如果对的链中的最后一个元素不是空列表,则该值被视为“不正确的列表”,并且将以不同的方式打印:
(quote (1 . (2 . 3)))
==> '(1 2 . 3)
(cons 1 (cons 2 3))
==> '(1 2 . 3)