函数中的setf不起作用

时间:2013-11-19 14:41:00

标签: lisp common-lisp

我定义了一个特殊变量* unsorted-lst *和一个在我的脚本中重置此变量的函数:

(defparameter *unsorted-lst* nil)

(defun reset-to-unsorted-list ()
  (setf *unsorted-lst* '(1 3  0 22 3 1 3 299 31 5 0 3 7 96 24 44))
  (format t "after reset: ~a~%" *unsorted-lst*)
)

之后我将它们复制到SBCL控制台进行测试,我做了:

* (setf *unsorted-lst* '(1 2 3))
(1 2 3)
* (reset-to-unsorted-list)
after reset: (1 3 0 22 3 1 3 299 31 5 0 3 7 96 24 44)
NIL

到目前为止一切正常。然后我做了

* (setf (second *unsorted-lst*) 100)
100
* (reset-to-unsorted-list)
after reset: (1 100 0 22 3 1 3 299 31 5 0 3 7 96 24 44)
NIL

函数中的setf似乎不起作用,第二个元素值仍为100.这真让我感到困惑。我必须直接在控制台中键入setf命令才能进行更改:

* (setf *unsorted-lst* '(1 3 0 22 3 1 3 299 31 5 0 3 7 96 24 44))

(1 3 0 22 3 1 3 299 31 5 0 3 7 96 24 44)
* *unsorted-lst*
(1 3 0 22 3 1 3 299 31 5 0 3 7 96 24 44)

现在它有效。我不知道它有什么不对?是否有一些对setf的误解?还是变量?

1 个答案:

答案 0 :(得分:9)

您需要将变量数据设置为新的新列表,这是文字数据的副本。不要让全局变量指向函数的本地文字数据。

您正在查看的是Common Lisp程序中的未定义行为。

您在函数中使用文字数据。稍后,您可以通过更改列表的第二个元素来修改此文字数据。究竟发生了什么是未申报的。一些可能的结果:

  • 数据与其他一些变量共享,都看到了变化。
  • 发生错误,因为文字数据可能在只读内存中
  • 数据已更改

许多实现只是更改文字数据。在这种情况下,函数的数据会发生变化。

如果希望函数重置变量值并创建非文字数据,则需要先复制文字列表。

CL-USER 30 > (defparameter *unsorted-lst* nil)
*UNSORTED-LST*

CL-USER 31 > (defun reset-to-unsorted-list ()
               (setf *unsorted-lst*
                     (copy-list '(1 3  0 22 3 1 3 299 31 5 0 3 7 96 24 44)))
               (format t "after reset: ~a~%" *unsorted-lst*))
RESET-TO-UNSORTED-LIST

CL-USER 32 > (setf *unsorted-lst* '(1 2 3))
(1 2 3)

CL-USER 33 > (reset-to-unsorted-list)
after reset: (1 3 0 22 3 1 3 299 31 5 0 3 7 96 24 44)
NIL

CL-USER 34 > (setf (second *unsorted-lst*) 100)
100

CL-USER 35 > (reset-to-unsorted-list)
after reset: (1 3 0 22 3 1 3 299 31 5 0 3 7 96 24 44)
NIL