Основной вопрос о списке ассоциаций в 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. Как определено, это верно, если есть одно или несколько значений.

Если, когда было несколько значений, вы вложили эти значения в другой список, тогда вам просто нужно будет выбрать их из этого списка, когда вы захотите их использовать. Это не даст вам ничего, и это сделает его отличным от случая с одним значением.