如何在Common Lisp中替换正在运行的函数?

时间:2012-01-16 00:25:17

标签: lisp common-lisp sbcl

假设我们使用SBCL的#save-lisp-and-die来创建服务器应用程序App1,它运行良好。现在我们想要在不停止App1的情况下用新版本替换函数#'func1。我们怎样才能在Common Lisp中做到这一点?

任何建议都表示赞赏!

2 个答案:

答案 0 :(得分:10)

我个人确保SWANK(SLIME的服务器部分)正在运行,以便我可以随时使用Emacs + SLIME连接到图像并重新定义我想要的任何内容。

(ql:quickload "swank")
(swank:start-server :port 1234) ;; listen for SLIME connections on port 1234

然后在Emacs中,您可以M-x slime-connect,并按照提示进行操作。

如果您因任何原因不想这样做,您的实施可能会提供特定的内容。

答案 1 :(得分:4)

您需要加载新的函数定义。然后立即提供新功能;代码将调用新加载的函数。

可以通过多种方式加载新函数定义:

  • (load (compile-file "file.lisp"))其中file.lisp是函数的源代码
  • (load "file.fasl")其中file.fasl是已编译的源代码
  • (eval (defun ...))

当然,也有例外和并发症:

  • 这不会取代之前正在运行的函数调用;例如,无限的事件循环不能以这种方式改变 - 它必须支持某种停止和调用新函数。但是,这种长期运行的功能很少见。它可以通过使用递归而不是循环来解决(但并非所有编译器都进行尾调用优化)。
  • 如果你某个地方抓住了一个指向函数的指针(例如,(function FOO),其中FOO是函数的名称),它将保留其旧值。为避免这种情况,请使用符号而不是函数指针(符号为funcall)。
  • 函数的代码是垃圾回收的主题。你应该注意不要留下对旧版本函数的引用。此外,如果不需要某些功能,您不应忘记fmakunbound符号。
  • 如果在编译时使用该函数,则还应重新加载所有受影响的代码
  • 如果您具有高级别的优化(默认情况下不是这样),编译器可能会将该功能内联到其他人中。当重新定义函数变为“未定义的行为”时,CLHS会区分这些案例。

但实际上,代码重新加载在大多数Common Lisp实现中都很有效。