Основной вопрос о списке ассоциаций в Lisp
Я читаю "Земля из Lisp" (которая, кстати, одна из лучших технических книг, которые я когда-либо читал), и я встречаю список ассоциаций
(defparameter *edges*
'((living-room (garden west door)
(attic upstairs ladder))
(garden (living-room east door))
(attic (living-room downstairs ladder))))
Во-первых, это список ассоциаций в Lisp той же концепции Java Map (привязка ключевого значения)?
Для ключа гостиной, как можно иметь более одного значения? почему бы не приложить значение к списку:
(living-room ((garden west door) (attic upstairs ladder)))
Ответы
Ответ 1
-
Да, список ассоциаций - это один из способов выражения ассоциаций ключевых значений. Другие структуры Общие Lisp предоставляет для этой цели списки свойств и хеш-таблицы.
-
Значение на самом деле уже содержится в списке. Алист - это в основном список пар, где автомобиль каждой пары является ключом, а cdr - значением, связанным с этим ключом. Если вы просмотрите ключ LIVING-ROOM с ASSOC и примените CDR к результату:
CL-USER> (cdr (assoc 'living-room *edges*))
((GARDEN WEST DOOR) (ATTIC UPSTAIRS LADDER))
Магия этого заключается в том, что пара, автомобиль которой living-room
и чья cdr - это список из двух элементов (garden west door)
и (attic upstairs ladder)
, также может рассматриваться как список трех элементов (living-room (garden west door) (attic upstairs ladder))
, из-за того, что списки построены из пар.
Обычно при представлении алистов в качестве цитируемых объектов вы видите элементы, явно обозначенные пунктирными парами, вместо того, чтобы записывать нотацию списка, например:
(defparameter *edges*
'((living-room . ((garden west door)
(attic upstairs ladder)))
(garden . ((living-room east door)))
(attic . ((living-room downstairs ladder))) ))
Ответ 2
ASSOC возвращает ячейку cons и, таким образом, включает как ключ, так и значение.
Причина в том, что это упрощает обновление значения (или ключа) разрушительно.
Здесь обновление скрыто за SETF:
CL-USER 11 > (defparameter *edges*
(copy-tree
'((living-room (garden west door)
(attic upstairs ladder))
(garden (living-room east door))
(attic (living-room downstairs ladder)))))
*EDGES*
CL-USER 12 > (assoc 'living-room *edges*)
(LIVING-ROOM (GARDEN WEST DOOR) (ATTIC UPSTAIRS LADDER))
CL-USER 13 > (cdr (assoc 'living-room *edges*))
((GARDEN WEST DOOR) (ATTIC UPSTAIRS LADDER))
CL-USER 14 > (setf (cdr (assoc 'living-room *edges*)) '((garden east door)))
((GARDEN EAST DOOR))
CL-USER 15 > (cdr (assoc 'living-room *edges*))
((GARDEN EAST DOOR))
Ответ 3
Во-первых, это список ассоциаций в Lisp той же концепции Java-карты (привязка ключевого значения)?
Карта Java - это интерфейс. Алист - это особый способ использования (связанного) списка для хранения пар ключ-значение. Я не думаю, что у Java есть встроенные Карты, обладающие теми же свойствами, что и у алиста, но писать их не составит труда. Поскольку список alist является списком, все функции и свойства списков сохраняются.
Для ключа гостиной, как можно иметь более одного значения? почему бы не приложить значение к списку:
Алист не является частью синтаксиса Lisp. Это всего лишь список, поэтому вы можете поместить все, что хотите, в CDR каждого элемента. В этом случае это еще одна ячейка CONS. ASSOC
просто смотрит на ЦАР каждого элемента.
(assoc 'living-room *edges*)
(LIVING-ROOM (GARDEN WEST DOOR) (ATTIC UPSTAIRS LADDER))
Ответ 4
Список ассоциаций по идее похож на карту, поскольку оба ассоциируют ключи со значениями.
В другом списке нет необходимости заключать несколько значений, поскольку это изменяет значение значения. Я не знаком с этой книгой, но кажется, что путь *EDGES*
определен, автор хочет
(cdr (assoc 'Foobar *edges*))
чтобы быть списком мест, которые вы можете получить от Foobar. Как определено, это верно, если есть одно или несколько значений.
Если, когда было несколько значений, вы вложили эти значения в другой список, тогда вам просто нужно будет выбрать их из этого списка, когда вы захотите их использовать. Это не даст вам ничего, и это сделает его отличным от случая с одним значением.