如何用 nil 创建点对

How to create dotted pair with nil

我有以下形式的队列名称列表:

'("foo" "bar")

我正在尝试通过以下方式将队列存储为关联列表:

'(("foo" . nil) ("bar" . nil))

基本上它是一个关联列表,其中包含当前为空的队列 "foo" 和 "bar"。当 Bob 和 Alice 在 "foo" 队列中时,它应该如下所示。

'(("foo" . ("alice" "bob")) ("bar" . nil))

如何创建这个结构?我试图通过写作来实现这一目标:

(mapcar #'(lambda (x) (cons x ''nil)) '("foo" "bar"))

返回

'(("foo" QUOTE NIL) ("bar" QUOTE NIL))

这可能不是我想要的,因为当我试图将 Bob 推送到 "foo" 队列时,它并没有像我想要的那样工作。

* (setf *tmp* '(("foo" . 'nil) ("bar" . 'nil)))
(("foo" QUOTE NIL) ("bar" QUOTE NIL))
* (push "bob" (caddr (assoc "foo" *tmp* :test #'string=)))
* *tmp*
(("foo" QUOTE ("bob")) ("bar" QUOTE NIL))

如何在点后创建带有空列表的点对?

编辑: 实际上,当我将 assoc 列表存储为 class 插槽时,它看起来不错。

* (describe myClassInstance)
;; ...
QUEUES    = (("foo" . 'NIL) ("bar" . 'NIL))
;; ...

然而,在将 Bob 添加到 "foo" 队列之后,所有队列都被更改了。

* (push "bob" (caddr (assoc "foo" (slot-value myClassInstance 'testClass::queues) :test #'string=))))
* (describe myClassInstance)
;; ...
QUEUES    = (("foo" . '("bob") ("bar" . '("bob"))
;; ...

这里刚刚发生了什么?看起来所有队列的 cdr 部分都是一个符号,当我在一个地方("foo" 队列)更改它的值时,它在所有地方(所有队列)都被更改。有什么意义吗?

我认为您可能将结构与其印刷表示混淆了。 (cons x nil)'(x . nil) 相同,与 '(x) 相同。它们都将打印为 (x).

如果你想打印成 '(x . nil) 你可以为它写一个打印函数,但是表示完全没问题。

cdr为nil的缺点与单元素列表完全相同。这就是列表的定义方式。

换句话说,(cons x nil)(list x)是一样的。你可以想象这样的结果:

+-------+
| x |nil|
+-------+

因此 cdr 是列表的虚线对也只是一个列表。

换句话说,'(("foo" . nil) ("bar" . nil))'(("foo") ("bar")) 完全相同,即使前一种表示法可能更能表达您将其视为列表的意图。

同理,'(("foo" . ("alice" "bob")) ("bar" . nil))'(("foo" "alice" "bob") ("bar"))完全相同。

这意味着您可以完全按照自己的意愿创建数据结构,但您可以使用 e。 G。 list 而不是 (lambda (x) (cons x nil))(对于单个参数是相同的)。

(defun make-queues (&rest names)
  (mapcar #'list names))

您也可以只推送到 assoc 在名称下找到的元素:

(defun add-to-queue (queues queue-name item)
  (push item (cdr (assoc queue-name queues :test #'equal))))

(defun get-queue (queues queue-name)
  (cdr (assoc queue-name queues :test #'equal)))

您最后遇到的问题是您将文字放入列表并尝试对其进行修改:您将仅包含 nil 的相同 文字列表 放入列表的每个元素。

比较点

CL-USER 48 > (sdraw '(("foo" . ("alice" "bob")) ("bar" . nil)))

[*|*]---------------------------->[*|*]--->NIL
 |                                 |
 v                                 v
[*|*]--->[*|*]---->[*|*]--->NIL   [*|*]--->NIL
 |        |         |              |
 v        v         v              v
"foo"    "alice"   "bob"          "bar"

无点

CL-USER 49 > (sdraw '(("foo" "alice" "bob") ("bar")))

[*|*]---------------------------->[*|*]--->NIL
 |                                 |
 v                                 v
[*|*]--->[*|*]---->[*|*]--->NIL   [*|*]--->NIL
 |        |         |              |
 v        v         v              v
"foo"    "alice"   "bob"          "bar"

因此,这两种表示法都描述了相同的 cons 结构。