Я обязательного происхождения, но в эти дни пробуя мои руки на LISP (язык Common LISP)
Я читал здесь о cons
это
(недостатки x L):
Учитывая x объекта LISP и список L, оценивая (подставляет x L) создает список, содержащий x сопровождаемый элементами в L.
Когда я намеренно не использовал список в качестве второго аргумента т.е. когда я использовал
(cons 'a 'a)
Я ожидал ошибку, но стоп! Я добрался (A . A)
.
Чему скучали по мне и что (A . A)
?
Cons
создает «cons-ячейку». Поначалу это не имеет никакого отношения к спискам. Консольная ячейка - это пара двух значений. Консольная ячейка представлена в письменной форме «пунктирной парой», например (A. B)
, который содержит два значения 'A
и ' B
.
Два места в cons-ячейке называются «car» и «cdr». Вы можете визуализировать такую cons-ячейку как разделенный пополам блок:
car cdr
+-----+-----+
| A | B |
+-----+-----+
В Лиспе значение также может быть ссылкой на что-то еще, например, другую cons-ячейку:
+-----+-----+ +-----+-----+
| A | --------> | B | C |
+-----+-----+ +-----+-----+
Это будет представлено в форме «пары точек» как (A. (B. C))
. Вы можете продолжить так:
+-----+-----+ +-----+-----+ +-----+-----+
| A | --------> | B | --------> | C | D |
+-----+-----+ +-----+-----+ +-----+-----+
Это (A. (B. (C. D)))
. Как вы можете видеть, в такой структуре значения всегда находятся в машине
cons-ячейки, а cdr
указывает на остальную часть структуры. Исключением является последнее значение, которое находится в последнем cdr
. Однако нам не нужно это исключение: в Лиспе есть специальное значение NIL
, которое означает «ничего». Поместив NIL
в последний cdr
, вы получите удобное контрольное значение, а все ваши значения будут помещены в car
s:
+-----+-----+ +-----+-----+ +-----+-----+ +-----+-----+
| A | --------> | B | --------> | C | --------> | D | NIL |
+-----+-----+ +-----+-----+ +-----+-----+ +-----+-----+
Так строится список в Лиспе. Поскольку (A. (B. (C. (D. NIL))))
немного громоздко, его также можно представить просто как (A B C D)
. NIL
также называется пустым списком ()
; это заменяемые обозначения для одного и того же.
Теперь вы можете понять, почему (cons x list)
возвращает другой список. Cons
просто создает другую cons-ячейку с x
в car
и ссылкой на список
в cdr
:
+-----+-----+
| X | --------> list
+-----+-----+
и если список
равен (AB)
, он работает как:
+-----+-----+ +-----+-----+ +-----+-----+
| X | --------> | A | --------> | B | NIL |
+-----+-----+ +-----+-----+ +-----+-----+
Итак, (cons x '(ab))
оценивается как (xab)
.
Списки - это лишь одно из самых распространенных способов использования cons-ячеек. Вы также можете создавать произвольные деревья из cons-ячеек, круговых списков или любого ориентированного графа.
'a
- это атом лиспа, а (A. A)
- это вырожденный список, называемый cons-ячейкой или «пунктирной парой». Поскольку вы не передали список для аргумента L
в (cons x L)
, вы вернули ячейку.
(CONS x L)
Для заданных x и L функция CONS возвращает новую cons-ячейку с x как CAR этой ячейки и L как CDR этой ячейки.
Списки представляют собой связанные цепочки cons-ячеек.
CL-USER 141 > (sdraw '(a b c))
[*|*]--->[*|*]--->[*|*]---> NIL
| | |
v v v
A B C
CL-USER 142 > (sdraw (cons 'foo '(a b c)))
[*|*]--->[*|*]--->[*|*]--->[*|*]---> NIL
| | | |
v v v v
FOO A B C
Если CONS получает в качестве аргумента два символа, это выглядит так:
CL-USER 143 > (sdraw (cons 'foo 'bar))
[*|*]---> BAR
|
v
FOO