CLISP allows us to do
(compile nil #'(lambda(x) (+ x 1)))
This returns a compiled function object:
#<COMPILED-FUNCTION NIL>
Is it possible to export this as a binary string, in order to persist it? Say, saving it in a database, and later be able to load and run the compiled function.
Yes, in CLISP you can:
> (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
This is portable across all platforms supported by CLISP, and as long as the CLISP bytecode version is the same (it does not change at every release).
As Rainer said, other CL implementation do not necessarily support this, but you can certainly put your function into a file, compile the file, and read in the string:
(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)))
To recover the function, you would need to do use load
:
(with-input-from-string (s (function-string *my-function*))
(load s))
(fdefinition 'my-tmp-func)
Notes:
function-lambda-expression
's value can legitimately be always nil
in a given implementation!