Основной вопрос о списке ассоциаций в Лиспе
Я читаю "Землю Лиспа" (кстати, одну из лучших технических книг, которые я когда-либо читал), и мне попался список ассоциаций.
(defparameter *edges*
'((living-room (garden west door)
(attic upstairs ladder))
(garden (living-room east door))
(attic (living-room downstairs ladder))))
Во-первых, является ли список ассоциаций в Лиспе той же концепцией Java Map (привязка ключ-значение)?
Для ключа от гостиной, как можно иметь более одного значения? почему бы не заключить значение в список:
(living-room ((garden west door) (attic upstairs ladder)))
4 ответа
Да, список ассоциаций является одним из способов выражения ассоциаций ключ-значение. Другими структурами, которые предоставляет Common Lisp для этой цели, являются списки свойств и хеш-таблицы.
Значение на самом деле уже содержится в списке. Alist - это, по сути, список пар, где ключом является автомобиль каждой пары, а cdr - это значение, связанное с этим ключом. Если вы посмотрите на ключ LIVING-ROOM с ASSOC и примените CDR к результату:
CL-USER> (cdr (ассоциированная гостиная * ребра *)) ((САД ЗАПАДНАЯ ДВЕРЬ) (ТРЕТЬЯ ЛЕСТНИЦА НАВЕРХ))
Волшебство за этим заключается в том, что пара, чья машина living-room
и чей CDR является списком двух элементов (garden west door)
а также (attic upstairs ladder)
может также рассматриваться как список из трех элементов (living-room (garden west door) (attic upstairs ladder))
из-за того, что списки построены из пар.
Обычно при представлении списков в виде объектов в кавычках вы видите элементы, явно изображенные точечными парами, а не обозначения списком, например:
(дефараметр * ребра * '((гостиная. ((западная дверь сада) (мансардная лестница наверх))) (сад. ((гостиная восточная дверь))) (чердак. ((лестница в гостиную внизу)))))
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))
Список ассоциаций похож на концепцию карты, поскольку оба ассоциированных ключа со значениями.
Нет необходимости заключать несколько значений в другой список, потому что это меняет значение значения. Я не знаком с этой книгой, но похоже, что *EDGES*
определяется, автор хочет
(cdr (assoc 'Foobar *edges*))
быть списком мест, которые вы можете получить от Foobar. Как определено, это верно, если есть одно или несколько значений.
Если при наличии нескольких значений вы вложили эти значения в другой список, то вам просто нужно будет выбрать их из этого списка, когда вы захотите их использовать. Это не даст вам ничего, и это будет отличаться от случая с одним значением.
Во-первых, является ли список ассоциаций в Лиспе той же концепцией Java Map (привязка ключ-значение)?
Карта Java - это интерфейс. Alist- это особый способ использования (связанного) списка для хранения пар ключ-значение. Я не думаю, что в Java есть какие-либо встроенные Карты, имеющие те же свойства, что и в alist, но написать их будет несложно. Поскольку alist является списком, все функции и свойства списков по-прежнему сохраняются.
Для ключа от гостиной, как можно иметь более одного значения? почему бы не заключить значение в список:
Alist не является частью синтаксиса Lisp. Это просто список, так что вы можете поместить все, что хотите, в CDR каждого элемента. В данном случае это еще одна ячейка CONS. ASSOC
просто смотрит на автомобиль каждого элемента.
(assoc 'living-room *edges*)
(LIVING-ROOM (GARDEN WEST DOOR) (ATTIC UPSTAIRS LADDER))