lambda - 如何在保留捕获的变量的同时更改 lambda 中的代码?

标签 lambda closures lisp common-lisp live-update

假设我有一个运行我的 Common Lisp 代码的进程的 REPL。它可能正在运行 SWANK/SLIME。

我想在我的实时进程中更新一个用 defun 定义的函数。该函数可能已经捕获了 let 绑定(bind)中的一些变量。本质上,这个函数是一个闭包。

如何更新闭包中的代码而不丢失它捕获的数据?

2019-11-03:我在下面选择了一个答案,但我建议阅读所有答案。每个人都有有趣的见解。

最佳答案

基本上你不能,这是避免在 LET 中使用 DEFUN 的原因之一。

可以创建一个新闭包并尝试将状态从旧闭包复制到新闭包中。

一个问题是可移植的 Common Lisp 不允许对闭包进行大量动态访问。人们不能“进入”闭包并从外部添加或替换某些东西。没有为闭包定义反射或内省(introspection)操作。

因此,您以后想要对闭包执行的所有操作都需要已经存在于闭包生成代码中。

假设您有这段代码:

(let ((foo 1))
  (defun add (n)
    n))

现在我们确定 add 是错误的,应该实际添加一些东西吗?

我们想要这样的效果:

(let ((foo 1))
   (defun add (n)
     (+ n foo)))

我们如何修改原始文件?我们基本上不能。

如果我们有:

(let ((foo 1))
  (defun get-foo ()
    foo)
  (defun add (n)
    n))

我们可以这样做:

(let ((ff (symbol-function 'get-foo))
      (fa (symbol-function 'add)))
  (setf (symbol-function 'add)
     (lambda (n)
       (+ (funcall fa n) (funcall ff)))))

这然后定义了一个新函数 add,它可以通过旧函数访问闭包值 - 在它自己的闭包中捕获。

风格

不要使用 LET 封闭的 DEFUN:

  • 它们很难修改
  • 编译器不会将 DEFUN 视为顶级形式
  • 影响难以控制
  • 我们想对多次加载代码做什么?
  • 它们很难调试
  • Common Lisp 有处理全局状态的方法。

关于lambda - 如何在保留捕获的变量的同时更改 lambda 中的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58619515/

相关文章:

lisp - 从嵌套列表中删除

c# - lambda 外部子查询迭代变量评估的次数

android - 如何在android中使用lambda表达式

没有全局变量的 JavaScript 前端模块化

swift - 闭包和静态函数

function - 我可以有一个在 Rust 中不被类型化为闭包的匿名函数吗?

list - Racket - 列表的输出内容

lisp - 当我尝试在 Windows 7 : 'rm' is not recognized 中克隆 HN 时出错

c# - 如何将这个双 foreach 循环转换为 lambda 表达式?

java - 如何使用 Java 8 Stream/Lambda 计算整数中尾随零的数量?