在数据库中存储 Lisp 编译函数

Storing a Lisp compiled function in a database

CLISP 允许我们做

(compile nil #'(lambda(x) (+ x 1)))

这个returns一个编译函数对象:

#<COMPILED-FUNCTION NIL>

是否可以将其导出为二进制字符串,以便持久保存?比如说,将它保存在数据库中,以后可以加载和 运行 编译函数。

不在可移植的 Common Lisp 中。

而是将函数写入文件,使用 COMPILE-FILE 编译文件。然后你在文件系统上有了编译后的代码。您可以稍后加载文件和 运行 函数。您还可以将文件内容存储到数据库中。如果您以后需要它,则需要将数据从数据库导出到文件中,然后调用 LOAD 加载文件。

CLISP

是的,在 CLISP 中您可以:

> (defparameter *my-function* (compile nil #'(lambda(x) (+ x 1))))
*MY-FUNCTION*
> *MY-FUNCTION*
#<COMPILED-FUNCTION NIL>
> (write-to-string *my-function* :readably t :pretty nil)
"#Y(|COMMON-LISP|::|NIL| #15Y(00 00 00 00 01 00 00 00 20 02 AD 32 B1 19 02) () (|COMMON-LISP|::|T| |COMMON-LISP|::|NIL| |COMMON-LISP|::|NIL|))"
> (defparameter *my-function-1* (read-from-string (write-to-string *my-function* :readably t)))
*MY-FUNCTION-1*
> (funcall *my-function-1* 10)
11

这可以跨 CLISP 支持的所有平台移植,只要 CLISP 字节码版本相同(不会在每个版本中更改)。

其他实现

正如Rainer所说,其他CL实现不一定支持这个,但你当然可以把你的函数放到一个文件中,编译文件,然后读入字符串:

(defun function-string (func)
  (let ((lambda-expr (function-lambda-expression func)))
    (unless lambda-expr
      (error "no lambda expression for ~S" func))
    (let ((tmp-file "tmp.lisp") comp-file ret)
      (with-open-file (o tmp-file :direction :output)
        (write (list* 'defun my-tmp-func (cdr lambda-expr))
               :stream o :readably t))
      (setq comp-file (compile-file tmp-file))
      (with-open-file (compiled comp-file :direction :input
                                :element-type '(unsigned-byte 8))
        (setq ret (make-array (file-length compiled)
                              :element-type '(unsigned-byte 8)))
        (read-sequence ret compiled))
      (delete-file tmp-file)
      (delete-file comp-file)
      ret)))

要恢复功能,您需要使用 load:

(with-input-from-string (s (function-string *my-function*))
  (load s))
(fdefinition 'my-tmp-func)

备注:

    在给定的实现中,
  1. function-lambda-expression 的值可以合法地 always nil
  2. 如果实现编译为本机代码,则上述字符串将与平台相关。
  3. 我忽略了包裹问题...