【问题标题】:Defining setf for function in closure为闭包中的函数定义 setf
【发布时间】:2014-11-09 15:02:15
【问题描述】:

如果我创建这样的闭包,

(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 的第 i 个元素:

(h 1)  ;; => 5
(h 2)  ;; => 5

但尽管setf 扩展可以正常工作并正确设置a 的第i 个元素,但它也会在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 中,该示例运行良好。

我在写了几年 Scheme 之后又回到了 Common Lisp,所以我可能在概念上混合了这两种语言。我想我已经触发了根据规范未定义的行为,但我无法确切地看到我做错了什么。我将不胜感激!

【问题讨论】:

    标签: lisp closures common-lisp


    【解决方案1】:

    你的问题

    尝试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)))
    

    【讨论】:

    • 我明白了——你是对的。我想知道为什么CLISP和ECL让我改变值,当我在setf之后发出(h 1)时给了我10...
    猜你喜欢
    • 1970-01-01
    • 2018-08-12
    • 1970-01-01
    • 1970-01-01
    • 2012-07-12
    • 2018-07-10
    • 2013-12-03
    • 2017-06-22
    • 1970-01-01
    相关资源
    最近更新 更多