插入列表并不反映外部功能,而删除呢?

时间:2015-06-15 12:04:38

标签: list lisp common-lisp

我是Lisp的新手。通过函数删除列表中的项目会反映在函数外部,但插入不会。我怎样才能插入相同的内容?

例如

(defun test (a b)
  (delete 1 a)
  (delete 5 b)
  (append '(5) b)
  (member '5 b))

(setq x '(2 3 1 4))
(setq y '(8 7 5 3))

(test x y)

;;x and y after function ends
x
(2 3 4)
y
(8 7 3)

为什么不附加影响列表y?如何从函数中插入y?

1 个答案:

答案 0 :(得分:2)

追加不是假设来修改任何东西

  

为什么不附加影响列表y?

append 文档的第一句是(强调添加):

  

追加返回一个新列表,它是副本的串联。

没有人说过追加应该修改一个列表。

您无法更改其范围之外的词法绑定的值

  

如何从函数中插入y?

在最普遍的意义上,你不能。如果 y 的值是空列表,会发生什么?使用函数(而不是宏)无法在Common Lisp中创建类似的工作:

(let ((list '())
  (insert list 1)
  l)
;=> (1)

函数不能改变其范围 1 之外的变量的词法绑定,因此 insert 无法更改 list 。

当然,您可以修改对象的内部结构,因此如果 list 的值是某些非空列表,则可以修改该列表的结构。 list 的值不会改变(即,它仍然是相同的cons单元格),但该cons单元格所代表的列表将会改变。例如,

(defun prepend (list element)
  (let ((x (first list)))
    (setf (rest list) (list* x (rest list))
          (first list) element)))

(let ((list (list 1 2)))
  (prepend list 'a)
  list)
;=> (a 1 2)

保存返回值

一般来说,你需要养成保存功能结果的习惯。大多数函数不会修改它们的参数,因此您需要保存它们的结果。某些功能允许,但不是必需,以修改其参数,并且不必以可预测的方式进行修改,因此您还需要保存其结果。例如,您的代码可能是:

(defun test (a b)
  (setf a (delete 1 a))
  (setf b (delete 5 b))
  (setf b (append '(5) b))
  (member 5 b))

(test ...)
;=> true

1 你可以通过给它一个关闭绑定等的setter函数来解决这个问题。但是那些技术将是变通方法