1

我正在尝试在 Common Lisp 中编写一个从列表中删除项目的函数。这是我到目前为止所写的:

(defun aux-remove-fio (lst toremove)
   (if (equal (first lst) toremove)
       (pop lst)
       (aux-remove-fio (rest lst) toremove))))

当我测试函数时,结果如下:

CG-USER(49): a3
((1 (1 . 1) (1 . 2)) (2 (2 . 1) (1 . 2)))
CG-USER(50): (pop a3)
(1 (1 . 1) (1 . 2))
CG-USER(51): a3
((2 (2 . 1) (1 . 2)))
CG-USER(52): (setf a3 '((1 (1 . 1) (1 . 2)) (2 (2 . 1) (1 . 2))))
((1 (1 . 1) (1 . 2)) (2 (2 . 1) (1 . 2)))
CG-USER(53): (aux-remove-fio a3 '(1 (1 . 1) (1 . 2)))
(1 (1 . 1) (1 . 2))
CG-USER(54): a3
((1 (1 . 1) (1 . 2)) (2 (2 . 1) (1 . 2)))

谁能解释为什么我的功能不起作用?

4

2 回答 2

2

是的。你的函数改变了它的局部变量的值,lst---仅此而已。

这是一个更简单的示例,显示相同的内容:

(setq a3 '(1 2 3)) ; (1 2 3)
(defun foo (xs) (setq xs (cdr xs))) ; Change value of xs.

;; Change value of xs to (2 3).  Its initial value is the value of a3, i.e., (1 2 3)
(foo a3)
a3 ; => (1 2 3)

foo被调用之后,a3仍然指向原来的 cons 单元,其 car 为 1,其 cdr 与之前的 cons 单元相同,与 car 2 等相同。你所做的一切我让局部变量xs指向它原来的 cons 单元的 cdr指向,这与a3指向的缺点单元格相同。

如果你想让你的函数改变全局变量的值a3,那么直接这样做:

(defun foo () (pop a3))

或者,如果您只想要一个从特殊变量的列表值中弹出第一个元素的函数,那么您就有这样一个函数:pop--- 只需使用(pop a3).

如果你想要一个函数来改变你传递给它的全局变量的值,那么传递变量(即符号)而不是它的值:

(defun foo (var)
  (let* ((val   (symbol-value var))
         (head  (car val)))
    (set var (cdr val))
    head))

(foo 'a3) ; Pop off a3's head and return it.
a3 ; Now a3 has lost its head.

这个定义foo类似于 的简单形式pop,只是它是一个函数,所以计算它的参数。

于 2013-11-11T05:32:27.117 回答
0

这是我的简单解决方案。我在 REPL 中定义了一个函数

CL-USER> (defun remove-element (mylist n)
           (append
            (subseq mylist 0 n)
            (subseq mylist (1+ n))))

然后运行它(你的 Lisp 实现上的错误可能会有所不同)

CL-USER> (remove-element '(1 2 3 4 5) 0)
(2 3 4 5)
CL-USER> (remove-element '(1 2 3 4 5) 1)
(1 3 4 5)
CL-USER> (remove-element '(1 2 3 4 5) 5)
; Evaluation aborted on #<SB-KERNEL:BOUNDING-INDICES-BAD-ERROR ...
CL-USER> (remove-element '(1 2 3 4 5) -1)
; Evaluation aborted on #<TYPE-ERROR ... 
于 2013-11-14T23:00:50.100 回答