Lisp中的“关联列表”和Java中的Map有什么关系?

13

我正在阅读《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"键,如何有多个值?为什么要用列表括起来?

'(living-room
   ((garden west door)
    (attic upstairs ladder)))
4个回答

13
  1. 是的,关联列表是一种表示键值关联的方式之一。Common Lisp提供的其他结构包括属性列表和哈希表。

  2. 实际上,该值已经包含在一个列表中。alist本质上是一组成对的列表,其中每个对的car是键,cdr是与该键关联的值。如果使用ASSOC查找键LIVING-ROOM并对结果应用CDR:

CL-USER> (cdr (assoc 'living-room *edges*))
((GARDEN WEST DOOR) (ATTIC UPSTAIRS LADDER))

这背后的魔法在于一个其car是living-room,cdr是由两个元素(garden west door)(attic upstairs ladder)所组成的列表,也可以被视为三个元素的列表(living-room (garden west door) (attic upstairs ladder)),这是由于列表是由成对的构造而成的方式所致。

通常,在将alists表示为引用对象时,您会看到元素明确地用点对表示,而不是像列表符号那样进行双关语处理,如下所示:

(defparameter *edges* 
  '((living-room . ((garden west door)
                    (attic upstairs ladder)))
    (garden . ((living-room east door))) 
    (attic . ((living-room downstairs ladder))) ))

啊,你比我早几分钟了!是的,不使用点对语法也让我一时摸不着头脑——好观察! - Ken
如果我想要获取值,为什么要使用cdr?assoc应该可以获取值,对吗? - Chiron
2
ASSOC 命令可以获取到 记录。然后您需要使用 CAR 或 CDR 命令来获取键/值。 - Nietzche-jou

6

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))

1
首先,Lisp中的关联列表是否与Java的Map(键值绑定)概念相同?
Java的Map是一个接口。alist是一种使用(链接)列表存储键值对的特定方式。我认为Java没有任何内置的Maps具有与alist相同的属性,但编写一个不难。由于alist是一个列表,因此所有列表的函数和属性仍然有效。
对于客厅钥匙,如何可能有多个值?为什么不用列表括起来?
alist不是Lisp语法的一部分。它只是一个列表,因此您可以在每个元素的CDR中放置任何内容。在这种情况下,它是另一个CONS单元格。ASSOC只查看每个元素的CAR。
(assoc 'living-room *edges*)
(LIVING-ROOM (GARDEN WEST DOOR) (ATTIC UPSTAIRS LADDER))

1
一个关联列表在概念上类似于映射,因为两者都将键与值相关联。
无需将多个值包含在另一个列表中,因为这会改变该值的含义。我不熟悉这本书,但看起来作者定义*EDGES*的方式是这样希望的。
(cdr (assoc 'Foobar *edges*))

这将是一个可以从Foobar获取的地方列表。根据定义,如果存在单个或多个值,则为真。

如果存在多个值,那么当您想要使用它们时,您可以将这些值嵌套在另一个列表中,然后只需从该列表中选择它们即可。它不会给您任何东西,并且它会使其与单个值的情况不同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接