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

时间:2015-08-06 09:43:34

标签: binary lisp persistence common-lisp clisp

CLISP允许我们做

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

这将返回一个已编译的函数对象:

#<COMPILED-FUNCTION NIL>

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

2 个答案:

答案 0 :(得分:5)

不在便携式Common Lisp中。

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

答案 1 :(得分:4)

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的值可以合法地始终 nil
  2. 如果实现编译为本机代码,则上述字符串将取决于平台。
  3. 我掩饰了包装问题......