Scheme宏 - 在转换中配对但列表作为输出?

时间:2011-08-28 00:05:06

标签: macros scheme

假设我在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)

这到底发生了什么?为什么输出是一个列表而不是一对?

2 个答案:

答案 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)