如果我创造了这样的结局,
(let ((A (make-array '(10) :initial-element 5)))
(defun h (i)
(aref a i))
(defsetf h (i) (x) `(setf (aref ,a ,i) ,x)))然后,如我所料,(h i)将返回a的第一个元素。
(h 1) ;; => 5
(h 2) ;; => 5但是,尽管setf展开符号正常工作,并正确设置了a的第一个元素,但它也会在SBCL中产生一个警告:
(setf (h 1) 10)
; in: SETF (H 1)
; (SETF (AREF #(5 10 5 5 5 5 5 5 5 5) 1) #:G1124)
; --> LET* MULTIPLE-VALUE-BIND LET FUNCALL SB-C::%FUNCALL
; ==>
; ((SETF AREF) #:NEW0 #(5 10 5 5 5 5 5 5 5 5) 1)
;
; caught WARNING:
; Destructive function (SETF AREF) called on constant data.
; See also:
; The ANSI Standard, Special Operator QUOTE
; The ANSI Standard, Section 3.2.2.3
;
; compilation unit finished
; caught 1 WARNING condition在GCL中,会发出错误信号:
>(setf (h 1) 10)
Error:
Fast links are on: do (si::use-fast-links nil) for debugging
Signalled by LAMBDA-CLOSURE.
Condition in LAMBDA-CLOSURE [or a callee]: INTERNAL-SIMPLE-UNBOUND-VARIABLE: Cell error on A: Unbound variable:
Broken at LIST. Type :H for Help.
1 Return to top level. 在CLISP和ECL中,示例工作得很好。
在编写了几年的计划之后,我将返回Common,所以我可能在概念上将这两种语言混合在一起。我想我已经触发了根据规范未定义的行为,但我看不出我做错了什么。我很感激你能帮上忙!
发布于 2014-11-09 15:38:44
你的问题
尝试macroexpand通常具有指导意义。
(macroexpand '(setf (h 2) 7))
==>
(LET* ()
(MULTIPLE-VALUE-BIND (#:G655)
7
(SETF (AREF #(5 5 5 5 5 5 5 5 5 5) 2) #:G655)))如您所见,您的setf调用扩展为一个表单,它在一个文字数组上调用setf,这通常是一个错误的想法,事实上,这正是SBCL警告您的内容:
Destructive function (SETF AREF) called on constant data.请注意,尽管有警告,SBCL (以及其他一致的实现,如CLISP和ECL)将按您的预期执行。这是因为文字数组是由函数h可以访问的局部变量引用的。
解决方案
我建议你用一个函数代替
(let ((A (make-array '(10) :initial-element 5)))
(defun h (i)
(aref a i))
(defun (setf h) (x i)
(setf (aref a i) x)))https://stackoverflow.com/questions/26829564
复制相似问题