В упражнении SICP 2.26 с использованием DrScheme, почему cons возвращает список, а не пару списков?

В упражнении SICP 2.26 приведен этот код схемы:

(define x (list 1 2 3))
(define y (list 4 5 6))

Затем передается этот вызов cons:

(cons x y)

Я ожидал, что пара списков вернется, ((1 2 3) (4 5 6)), но интерпретатор дает, ((1 2 3) 4 5 6) ... список с 4 элементами, первый из которых является списком. Почему вы относитесь к другому? Я попытался найти другие ответы SICP для объяснения, но не смог найти что-то удовлетворительное. Так могут ли эксперты Scheme/ Lisp пролить свет на этот аспект минусов? Заранее благодарим за понимание.

Ответ 1

'((1 2 3) 4 5 6) - фактически пара списков. Вот еще один способ написать:

'((1 2 3) . (4 5 6))

Однако принтер избегает пунктирной парной записи, когда это возможно, поэтому вместо этого вы получаете первое представление. Правило:

'(x . (xs ...))
=>
'(x xs ...)

Для любых x и xs. Здесь x = '(1 2 3) и xs = '(4 5 6), поэтому вы получите ((1 2 3) 4 5 6).


Чтобы узнать, как связаны обозначения cons и dotted-pair, сократите проблему до '(1) и '(6). Самый низкий способ построить пару из них:

(cons (cons 1 '()) (cons 6 '()))

Здесь '() - ниль или пустой список. Если мы переведем это буквально в нотацию с пунктирной парой, получим следующее:

'((1 . ()) . (6 . ()))

Но поскольку принтер по возможности сворачивает нотацию с пунктирной парой, вы получаете это вместо:

'((1 . ()) . (6 . ()))
=>
'((1) . (6))    ; <-- x=1, xs=nothing; x=6, xs=nothing
=>
'((1) 6) ; <-- x=1, xs=6

Ответ 2

cons использует первый аргумент в качестве главы списка, а второй - как хвост.

Вы даете ему первый список (1 2 3), который будет составлять головку результирующего списка и второй список (4 5 6), который будет использоваться как хвост списка. Таким образом, вы заканчиваете с ((1 2 3) 4 5 6).

Вещь списков в виде раскладок слева направо, заканчивающихся пустым списком (представленный здесь o здесь), и посмотрите, как они объединяются.

 X=      Y=
 /\      /\
1 /\  + 4 /\    
 2 /\    5 /\  
  3  o    6  o

Затем вы создаете:

 /\
X  Y

Получение:

  /\
 /\ \
1 /\ \
 2 /\ \
  3  o/\
     4 /\
      5 /\
       6  o

который ((1 2 3) 4 5 6, если он представлен в скобках. И это пара списков.

Ответ 3

Я нашел диаграммы в Emacs Lisp учебнике, особенно полезно при обучении Lisp.

Ответ 4

Эй, я думаю, вы могли бы подумать об этом таким образом;

всякий раз, когда есть нуль, должна быть пара скобок, как следует:

(минус 1 (минус 2 ноль)) → (список 1 2)

(пусть ((x (список 1 2 3)) (y (список 4 5 6))))

1. (cons x y) → (cons (cons 1 (cons 2 (cons 3 ноль))) (минус 4 (минус 5 (минус 6 ноль)))) здесь первый ниль обозначает конец пары, который может быть выражен скобкой; тогда как второй ниль означает конец всей пары, который использует другую пару круглых скобок; так, ((1 2 3) 4 5 6)

2. (list x y) → (cons x (cons y nil); поскольку мы знаем, что x содержит nil, поэтому оно должно быть (1 2 3); вторая часть содержит два низа, поэтому ((1 2 3) (4 5 6));

внутреннее большинство nil означает внешнюю большую скобку;

Надеюсь, это поможет.

Ответ 6

попробуйте (список x y) Я уверен, что он работает с общим lisp, я не знаю о Scheme