Hello,<br><br>Just reporting something I've managed to do. I've created a project named storable-functions, it is in my github account:<br><a href="http://github.com/gugamilare/storable-functions/tree/master"><br>http://github.com/gugamilare/storable-functions/tree/master</a><br>
<br>I've managed to successfully write portable code (needs trivial-garbage, metatilities and cl-store) that can write functions into files - with the restriction of using a small set of macros to "mark" closures and the functions themselves. I believe it would be possible to add other serialization libraries as the backend (I programmed for that purpose - the code which depends on cl-store is small and separated in a asdf system named cl-store+functions) but right now only code for cl-store has been written. An extensive test suite has also been written, it needs lift.<br>
<br>This is the most simple storable function:<br><br><span style="font-family: courier new,monospace;">(st (lambda (a b)</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> (the fixnum (+ (the fixnum a)</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> (the fixnum b)))))</span><br><br>It is possible to use (st-lambda ...) instead of (st (lambda ...)). The next one uses a closure:<br><br><span style="font-family: courier new,monospace;">(st (let ((acc 0))</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> (declare (fixnum acc))</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> (st (lambda (&optional (diff 1))</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> (the fixnum (incf acc (the fixnum diff)))))))</span><br><br>Declarations are kept after restorage. Again, you can use (st-let ...) instead of (st (let ...)). And the next one ilustrates the most important achievement, multiple functions sharing a closure:<br>
<br><span style="font-family: courier new,monospace;">(st (let ((acc 0))</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> (declare (fixnum acc))</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> (list (st (lambda (&optional (diff 1))</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> (incf acc (the fixnum diff))))</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> (st (lambda (&optional (value 0))</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> (setf acc (the fixnum value)))))))</span><br>
<br>The two functions returned there share the same closure, and that will be true after restorage IF they are stored in the same file, e.g., in a list or in slots of a class instance. Nothing is guaranteed if you store one function in one file and the other function in another file and restore them.<br>
<br>Other closures supported are let*, labels, flet, macrolet and symbol-macrolet (the last two were not tested yet). Another feature is using st around a function call that possibly return a function. For instance:<br><br>
<span style="font-family: courier new,monospace;">(st (compose #'cadr #'reverse))</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">(st (curry #'list 1 2 3 4))</span><br>
<br>The arguments of the functions compose and curry can be easily stored in a file using cl-store. That is what this macro do here: it evaluates all the arguments of the function calls (binding them to a some variables), calls the function (e.g. compose) with the arguments <span style="font-family: arial,helvetica,sans-serif;">(</span><span style="font-family: courier new,monospace;"><span style="font-family: arial,helvetica,sans-serif;">#'cadr and #'reverse)</span></span> and, if the call returns a function (say, the function f), it makes the arrangements for storing the arguments when the function is to be stored. In order to restore the function f, it calls again the same function (e.g. compose) with the "same" arguments <span style="font-family: arial,helvetica,sans-serif;">(</span><span style="font-family: courier new,monospace;"><span style="font-family: arial,helvetica,sans-serif;">#'cadr and #'reverse) and </span></span>takes the returned values as being f. Fortunatelly, compose and curry do not have side effects, so there is no problem calling them every time the function f is stored to or restored from a file.<br>
<br>There is also a macro stq which stores the entire form (it does not evaluate and store the function arguments, instead it stores the whole form - it is intended to be used with macros), but it is not working yet, and I am tired to see what is going on right now.<br>
<br>In order to store / restore functions, the backend named <span style="font-family: courier new,monospace;">cl-store+functions:cl-store+functions</span> should be used. This backend is compatible with the default backend <span style="font-family: courier new,monospace;">cl-store</span> (except that register-code won't work for the new backend after loading the system cl-store+functions).<br>
<br>I guess that's all for now. Any suggestions, comments, bug fixes are welcome, as usual. Just e-mail me: <a href="mailto:gugamilare@gmail.com">gugamilare@gmail.com</a>.<br><br>Gustavo.<br>