演变Lisp镜像

11

我喜欢基于图像的语言的想法,最近我一直在使用sbcl玩弄Common Lisp。我在几个地方看到过这样一种说法:通过能够保存和加载虚拟机图像,您可以演变运行在该图像上的应用程序或应用程序集。

我知道如何将代码加载到图像中并运行它,slime使这种事情变得非常好,但我的问题是:如何确定图像中定义了哪些函数? 比如说,假设我想在运行了几天或几个月后更新一个函数,但我忘记了函数名。 有没有办法获取代码或仅获取在该图像中定义的函数的名称?

现在,我确实将代码编写为源文件,然后通过repl进行加载,因此我在那里有副本,但这似乎是一个显而易见的功能。

2个回答

13

在Common Lisp中有所谓的包(packages)的概念。包是符号的注册表,用作符号的命名空间。你可以请求Common Lisp列出所有的包。

CL-USER 1 > (list-all-packages)
(#<The SQL-COMMON package, 0/4 internal, 28/32 external>
 #<The LOOP package, 245/256 internal, 3/4 external>
 #<The COMM package, 0/4 internal, 940/1024 external>
 #<The REG package, 41/64 internal, 0/4 external>
 ...)

每个包在某个数据结构中存储了内部符号。你可以询问Common Lisp哪些符号在一个包中被内化了。

CL-USER 2 > (loop for symbol being
                each external-symbol in (find-package "COMMON-LISP")
             collect symbol)
(MAKE-ARRAY INVOKE-DEBUGGER STRING-TRIM ...)
为了使这更加容易,Common Lisp提供了函数APROPOS和APROPOS-LIST。
CL-USER 3 > (apropos "MAKE-LOCK")
MP::INTERNAL-MAKE-LOCK (defined)
MP:MAKE-LOCK (defined)
WWW-UTILS:MAKE-LOCK (defined)
MAKE-LOCK
RESOURCES::MAKE-LOCK (defined)
MINIPROC:MAKE-LOCK (defined)

函数、类等使用符号作为它们的标识符。您也可以查询一个符号,它代表哪个函数。

CL-USER 4 > (symbol-function 'www-utils:make-lock)
#<Function WWW-UTILS:MAKE-LOCK 41E006A69C>
有时候,Common Lisp 也会记录函数的定义。这时可以使用 FUNCTION-LAMBDA-EXPRESSION 函数来检索它。
CL-USER 5 > (defun foo (a) (* (sin a) a))
FOO

CL-USER 6 > (pprint (function-lambda-expression 'foo))

(LAMBDA (A)
  (DECLARE (SYSTEM::SOURCE-LEVEL #<EQ Hash Table{0} 41403151C3>))
  (DECLARE (LAMBDA-NAME FOO))
  (* (SIN A) A))

但是通常现代的Common Lisp实现并不会使用已记录的定义,而是记录每个Lisp构造的源位置。

大多数Common Lisp实现可以以特定于实现的方式跟踪源位置。

Common Lisp标准定义了一个名为ED的函数。

CL-USER 7 > (ed 'www-utils:make-lock)

这将调用一个编辑器(内部或外部),并应该打开该函数的源代码。为了使其正常工作,Common Lisp需要跟踪每个函数的源位置。接下来,编辑器需要访问该源代码。有时记录的位置是绝对路径/Users/joswig/lisp/utils.lisp。如果编辑器想要打开该文件,它应该是可访问的。但也可以使用逻辑路径名比如http:server;utils.lisp。然后将其转换为实际的物理路径名。这个转换稍后可以进行配置。因此,即使将Lisp移动到具有不同路径名的不同计算机上,配置逻辑路径名HTTP,Lisp仍然能够找到所有源代码,即使它在具有不同文件系统结构的不同计算机上。因此,为使其正常工作可能需要一些配置。但它是一个非常有用的功能,并且被广泛使用。

源代码的记录以及源位置的记录方式取决于实现并与其开发环境的功能相关。 更好的 Lisp实现在这个领域拥有很多特性。


5
你也可以使用 do-symbols 或 do-external-symbols,如果你更喜欢的话:
例如:
>> (do-external-symbols (s (find-package :foo-package)) (print s))

FOO-PACKAGE:XXX
FOO-PACKAGE:YYY
FOO-PACKAGE:ZZZ
NIL

其中XXX、YYY和ZZZ均为:foo-package包中的外部符号。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接