【问题标题】:How to create dotted pair with nil如何用 nil 创建点对
【发布时间】:2016-11-13 10:35:00
【问题描述】:

我有一个队列名称列表,格式如下:

'("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 列表存储为类插槽时,它看起来很好。

* (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)???为什么 nil 被引用两次?
  • '(foo . 'nil) 应该是什么?为什么引用 nil?
  • @RainerJoswig 我现在找不到源,但有一个地方我发现了这种方式,可以在最后得到零点对。这可能是问题所在,但我无法弄清楚如何用点后的空列表创建点对。
  • 想想吧。有意义吗?

标签: list linked-list lisp common-lisp cons


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

    换句话说,'(("foo" . nil) ("bar" . nil))'(("foo") ("bar")) 完全相同,即使前者可能更好地表达了您将其视为 alist 的意图。

    同理,'(("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 的相同 文字列表 放入 alist 的每个元素中。

    【讨论】:

    • 这太棒了。非常感谢您以如此清晰的方式向我澄清这一点。所以基本上每个列表都是一个列表?因为即使是单元素列表在点之后也包含“隐藏”nil
    • 不,alist 是 conses 的列表。列表可以是 cons 或 nil(空列表)。所以任何非空列表的列表也是一个alist。
    【解决方案3】:

    用点比较

    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 结构。

    【讨论】:

    • 谢谢!不知何故,大部分时间我都忘记了很棒的sdraw
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-07
    • 1970-01-01
    • 2012-03-02
    • 2015-05-18
    • 1970-01-01
    • 2017-05-20
    • 1970-01-01
    相关资源
    最近更新 更多