Хранение скомпилированной функции Lisp в базе данных

CLISP позволяет нам делать

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

Это возвращает объект скомпилированной функции:

#<COMPILED-FUNCTION NIL>

Можно ли экспортировать это как двоичную строку, чтобы сохранить это? Скажем, сохраняя его в базе данных, а затем сможете загружать и запускать скомпилированную функцию.

2 ответа

Решение

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 одинакова (она не меняется при каждом выпуске).

Другие реализации

Как сказал Райнер, другие реализации 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. Я замял вопрос о пакетах...

Не в портативном Common Lisp.

Вместо этого запишите функцию в файл, скомпилируйте файл с COMPILE-FILE, Тогда у вас есть скомпилированный код в файловой системе. Вы можете позже загрузить файл и запустить функцию. Вы также можете сохранить содержимое файла в базе данных. Если вам это понадобится позже, вам нужно будет экспортировать данные из базы данных в файл и вызвать LOAD загрузить файл.

Другие вопросы по тегам