首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CLISP中未编译的lambda函数文字源的意外修改?

CLISP中未编译的lambda函数文字源的意外修改?
EN

Stack Overflow用户
提问于 2015-01-19 21:57:00
回答 1查看 115关注 0票数 1

我编写了以下函数

代码语言:javascript
复制
(defun test (name)
  (let ((lst (list 'lambda '()
                   '(let ((slot name))
                     nil))))

     (setf (car (cdr (car (car (cdr (car (cdr (cdr lst)))))))) name)

     (let ((anonymous-function (eval lst)))
       (setf (fdefinition name) anonymous-function))))

如果运行(test 'a),结果是(在CLISP上) #<FUNCTION :LAMBDA NIL (LET ((SLOT A)) NIL)>;如果运行(test 'b),则结果是#<FUNCTION :LAMBDA NIL (LET ((SLOT B)) NIL)>。在这里之前没什么奇怪的。但是当我运行(fdefinition 'a)时,我得到了#<FUNCTION :LAMBDA NIL (LET ((SLOT B)) NIL)>;如果运行(fdefinition 'b),则得到了#<FUNCTION :LAMBDA NIL (LET ((SLOT B)) NIL)>。是不是很奇怪?难道不是#<FUNCTION :LAMBDA NIL (LET ((SLOT A)) NIL)>(fdefinition 'a)的答案吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-01-19 22:07:51

您正在修改文字数据(然后使用该数据作为lambda函数体的主体),这会产生未定义的结果。有关这方面的更多信息,请参见Unexpected persistence of data。这种情况有点令人惊讶,但似乎CLISP正在将实际的源(lst的值)保存在lambda函数中(而不是编译它,而不是复制它),所以当您修改代码块时,您会看到引用相同代码块的每个lambda函数的结果都会发生变化。列表只有一个实例(let((时隙名))),您正在创建的所有不同的lambda函数都共享它。当您修改单个列表时,所有使用它的lambda函数都会看到更改。

最简单的事情(即对代码的最小更改,但不一定是最好的解决方案)是使用copy-tree生成一个新的代码块:

代码语言:javascript
复制
  (let ((lst (copy-tree (list 'lambda '()
                              '(let ((slot name))
                                nil)))))
    ; ...

但是,我认为处理这一问题的最好方法是使用Common的词汇闭包,并完全避免使用eval

代码语言:javascript
复制
(defun test (name)
  (let ((f (lambda ()
             (let ((slot name))
               nil))))
    (setf (fdefinition name) f)))

代码语言:javascript
复制
CL-USER> (test 'a)
#<FUNCTION :LAMBDA NIL (LET ((SLOT NAME)) NIL)>
CL-USER> (test 'b)
#<FUNCTION :LAMBDA NIL (LET ((SLOT NAME)) NIL)>

虽然结果看起来是一样的,但是函数是不同的,因为它们捕获了不同的词汇环境,所以他们做他们应该做的事情。例如,看看如果主体返回变量的值会发生什么:

代码语言:javascript
复制
(defun test (name)
  (let ((f (lambda ()
             (let ((slot name))
               slot))))
    (setf (fdefinition name) f)))

代码语言:javascript
复制
CL-USER> (test 'a)
#<FUNCTION :LAMBDA NIL (LET ((SLOT NAME)) SLOT)>
CL-USER> (a)
A
CL-USER> (test 'b)
#<FUNCTION :LAMBDA NIL (LET ((SLOT NAME)) SLOT)>
CL-USER> (b)
B
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28034163

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档