【问题标题】:Why is setq not doing anything?为什么 setq 什么都不做?
【发布时间】:2021-05-06 07:53:12
【问题描述】:

我需要使用 setq 更新嵌套在另一个关联列表中的关联列表中的值。我还不知道该怎么做,但我在找出如何做的第一步没有奏效。

在这里尽可能简单地说是我尝试过的:

(defvar l (list 1 2 3))
(loop for x in l do (setq x 5))

我希望这会将 l 中的所有元素更新为 5,但是当我检查 l 的值时,它根本不会改变。如果它不适用于此示例,那么显然它不适用于我的嵌套 alists 场景。我如何循环 l 并更改元素? 此外,如果 l 没有更新,那么 (setq x ...) 甚至在做什么?

编辑我决定使用常规的关联列表继续前进,但我仍然卡住了

(defvar u (list (list 1 2) (list 3 4)))
(assoc 1 u)
=> (1 2)
(let ((a (assoc 1 u))) (setf (assoc u 1) (cons (car a) 5)))

我希望你更改为 ((1 5) (3 4)) 但我收到错误函数 (SETF ASSOC) 未定义。如果 assoc 没有内置的 setf 形式,那么肯定还有其他内置函数可以做到这一点吗?

【问题讨论】:

    标签: common-lisp


    【解决方案1】:
    (loop for x in l do (setq x 5))
    

    l 是一个外部变量。

    x 是一个局部变量。循环创建局部变量并将列表项绑定到每个循环循环中的变量。

    如果您设置变量x,那么您只需更改该变量绑定。它对列表没有影响,因为x 对元素有自己的引用。它不引用列表存储单元。

    【讨论】:

    • 最后一句话是可疑的。使用(setq l (list cons 1 2) (cons 3 4) (cons 5 6)))(loop for x in l do (setf (car x) 77)) 确实改变了l,所以x 确实引用了列表存储单元本身。
    • @WillNess:列表的内容,但不是列表本身。
    • 澄清属于答案。因为现在的答案具有误导性。
    【解决方案2】:

    首先,关联列表(reference)是一个列表,其中一个元素是一对cons,其中car就是所谓的key,而cdr。所以,如果你想建立一个键和值都是数字的关联列表,正确的形式是:

    (defvar *u* (list (cons 1 2) (cons 3 4))
    (assoc 1 *u*) ; => (1 . 2)
    

    这样,当您想修改与某个键关联的值时,可以使用rplacd 原语操作(reference),它替换 a 的cdr找到与assoc 的对。例如:

    (rplacd (assoc 1 *u*) 5)
    *u* ; => ((1 . 5) (3 . 4))
    

    请注意,setq 可用于修改变量,而不是数据结构,例如对或列表。

    【讨论】:

      【解决方案3】:

      我需要使用 setq 更新嵌套在另一个关联列表中的关联列表中的值。

      不适用于setqever,它会改变变量的绑定;但有时使用(setf (car ...(setf (cdr ...(这两个翻译成rplacarplacd)。

      为什么有时?取决于您是否有权访问结构本身或其副本。例如(loop for x on l do (setf car x) 5) 不会更新 l,但 (maplist #'(lambda(x) (setf (car x) 6)) l) 会更新,(setf (car l) 7) 也会更新。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-07-13
        • 2019-04-05
        • 1970-01-01
        • 1970-01-01
        • 2017-12-08
        • 1970-01-01
        • 1970-01-01
        • 2016-04-01
        相关资源
        最近更新 更多