为什么setq没有生效?如何修改Lisp中列表元素与关联表(alist)的值
问题1:循环遍历列表时
setq无法修改原列表元素 原因解释
loop for x in l 语法中,x是遍历过程中存储当前元素值的临时局部变量,setq x 5仅仅是将x的指向修改为5,完全没有修改原列表底层cons单元的内容,因此原列表不会发生变化。
正确实现
如果要原地修改列表元素,可以迭代列表的cons单元,直接修改每个单元的car值:
(defvar l (list 1 2 3)) ;; 用loop for on获取每个cons单元 (loop for cons-cell on l do (setf (car cons-cell) 5)) ;; 执行后l的值为 (5 5 5)
也可以用map-into函数批量修改:
(map-into l (lambda (orig-val) 5) l)
问题2:关联表(alist)修改报错
(SETF ASSOC) is undefined 原因解释
- Common Lisp标准没有内置
assoc对应的setf方法,不能直接通过setf (assoc ...)修改关联表 - 你写的代码中
assoc的参数顺序错误:assoc的参数顺序是(assoc 查找的key 关联表),你写的(assoc u 1)本身参数顺序颠倒,即使有对应的setf方法也无法正常运行
正确实现
方案1:直接修改assoc返回的条目
assoc返回的是关联表中匹配条目的直接引用,直接修改该条目的cdr即可实现值更新:
(defvar u (list (list 1 2) (list 3 4))) (let ((matched-entry (assoc 1 u))) ;; 存在匹配条目时修改值 (when matched-entry ;; 如果要得到(1 5)的结构就写(setf (cdr matched-entry) (list 5)) (setf (cdr matched-entry) 5))) ;; 执行后u的值为 ((1 . 5) (3 4))
方案2:整体替换关联条目
如果需要完整替换整个条目,可以先移除旧条目再添加新条目:
;; 先移除key为1的旧条目,再添加新的(1 5)条目 (setf u (acons 1 5 (remove 1 u :key #'car)))
内容的提问来源于stack exchange,提问作者Akasha
相关产品推荐
相关产品推荐

