関数の永続性を可能にする、Elephant などの Common Lisp 用の永続化ソリューションはありますか? 現在、私のアプリは識別子をデータベースに保存し、後で関数テーブルを検索しますが、この方法では動的に作成された関数を保存できません。
6 に答える
これはデータベースの永続化メカニズムではありませんが、ほとんどの Common Lisp には、関数を含むあらゆる種類のオブジェクトのFASLを記述する方法があります。例えば:
cl-user(1): (compile (defun hello () (format t "~&Hello~%")))
hello
nil
nil
cl-user(2): (excl:fasl-write (symbol-function 'hello) "/tmp/hello.fasl")
t
cl-user(3): (excl:fasl-read "/tmp/hello.fasl")
(#<Function hello @ #x1000a964d2>)
ストリームに書き込むことができるので (ここでは便宜上ファイルを使用しました)、それらのバイトを簡単にキャプチャして、必要に応じてデータベースに詰め込むことができます。
Pascal Bourguignon は、comp.lang.lisp に関する標準的な解決策を提供しました。基本的に、ソース フォームをファイルに書き込んでから、COMPILE
それを書き出す必要がありますLOAD
。
(defvar *anon*)
(defun save-anonymous-function (fname args body)
(let ((fname (make-pathname :type "LISP" :case :common :defaults fname)))
(with-open-file (src fname :direction :output
:if-does-not-exist :create :if-exists :supersede)
(print `(defparameter *anon* (lambda ,args ,body)) src))
(compile-file fname)))
次に、ファイルを読み取ってデータベースに保存する必要があります。それを元に戻すには、データベースから取得し、ロードする前にファイルに書き込む必要があります。
(defun load-anonymous-function (fname)
(let ((*load-verbose* nil)
(*anon* nil)) ; to avoid modifying the global one.
(load fname)
*anon*))
風邪はあなたが望むものかもしれません。これには、シリアライズ可能なクロージャーとシリアライズ可能な継続が含まれます。
関数は不透明なオブジェクトであるため、ファイルなどに保存することはできません。ただし、リストを保存し、データベースから取得したときにそれらをコンパイルすることはできます。
もちろん、これはクロージャを保存するのに役立ちません。それには、コードとともに字句環境を保存する必要がありますが、どちらにも(ポータブル)アクセス権はありません。保存されたリストからコンパイルするコードは、グローバルデータまたはデータベースに保存されたデータに完全に依存する必要があります。
ちなみに、シンボルをfuncallできるので、グローバル関数用の関数テーブルは必要ありません。
Lisp画像の保存を調べることができます。これにより、「後でLispプロセスを再開するのに十分な情報」を保存できます。関数を画像にロードした後、関数を保存することができます。
これはあなたが探していたものよりも少し進んでいるかもしれませんが、ここにプロセスの(非常に)簡単な紹介があります:コアイメージの保存
コードの保存はあまり良くない場合があることに注意してください。Zope の開発者は苦労してそれを学びました。