在数据库中存储 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)
备注:
在给定的实现中,function-lambda-expression
的值可以合法地 always nil
!
- 如果实现编译为本机代码,则上述字符串将与平台相关。
- 我忽略了包裹问题...
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)
备注:
-
在给定的实现中,
function-lambda-expression
的值可以合法地 alwaysnil
!- 如果实现编译为本机代码,则上述字符串将与平台相关。
- 我忽略了包裹问题...