Макросы схемы - пара в преобразовании, но перечислить в качестве вывода?

Допустим, у меня есть следующий макрос в схеме RS R 5:

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

Что именно здесь происходит? Почему выводится список, а не пара?


person Justin Ethier    schedule 28.08.2011    source источник


Ответы (2)


Может ли c быть (3 . ()) во втором случае? Я не уверен, но для меня это имеет смысл. И тогда цитирование (a b . c) будет (1 2 . (3 . ())), что означает (1 2 . (3)), а (3) - правильный список, так (1 2 3)?

person Ross Larson    schedule 28.08.2011
comment
да. На самом деле c - это _1 _--- лишних кавычек там быть не должно, но вы по сути правы. - person Ryan Culpepper; 28.08.2011

Чтобы увидеть, что здесь происходит, вам нужно знать, что список в Scheme представляет собой рекурсивную цепочку пар элементов и других списков. Любые данные, которые соответствуют форме списка, всегда будут печататься в виде списка. Как только вы узнаете, как строятся базовые списки, вы сможете увидеть, что происходит внутри вашего макроса.

Пары в схеме могут быть созданы с помощью оператора . или с помощью функции cons. Вот простая пара чисел:

(quote (1 . 2))
==> '(1 . 2)
(cons 1 2)
==> '(1 . 2)

Чтобы создать список из 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)
person Dan Cecile    schedule 28.08.2011