gpt4 book ai didi

lisp - 为闭包中的函数定义 setf

转载 作者:太空宇宙 更新时间:2023-11-03 18:48:08 26 4
gpt4 key购买 nike

如果我像这样创建一个闭包,

(let ((A (make-array '(10) :initial-element 5)))    
(defun h (i)
(aref a i))
(defsetf h (i) (x) `(setf (aref ,a ,i) ,x)))

然后,如我所料,(hi) 将返回 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,所以我可能在概念上混合了这两种语言。我想我已经触发了根据规范未定义的行为,但我无法确切地看到我做错了什么。我将不胜感激!

最佳答案

你的问题

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

关于lisp - 为闭包中的函数定义 setf,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26829564/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com