Welcome! Please see the About page for a little more info on how this works.

0 votes
in Libs by

I looked around and didn't see anything obvious. But, I am relatively new to Clojure and core.logic. Just want see if there is some simple way to store a logic db to a file. I want to store/retract facts in a logic db and save the entire db off occasionally for recovery purposes. Then, later, possibly restore that db to memory.

Thanks in advance for any help.

1 Answer

0 votes

Looks like nippy works with standard serialization, since the prolog fact db is implemented with clojure types that are already serializable.

(ns logos.serial
  (:require [taoensso.nippy :as nippy]
            [clojure.core.logic.pldb :as pldb]
            [clojure.core.logic :as log]

(defn freeze-to! [o target & {:keys [compressor] :or {compressor nippy/lz4hc-compressor}}]
  (with-open [buff (clojure.java.io/output-stream target)
              dos (java.io.DataOutputStream. buff)]
    (nippy/freeze-to-out! dos  o)))

(defn thaw-from! [target & {:keys [compressor] :or {compressor nippy/lz4hc-compressor}}]
  (with-open [fis (clojure.java.io/input-stream target)
              dis (java.io.DataInputStream. fis)]
    (nippy/thaw-from-in! dis )))

(pldb/db-rel man p)
(pldb/db-rel woman p)
(pldb/db-rel likes p1 p2)
(pldb/db-rel fun p)

(def facts0
   [man 'Bob]
   [man 'John]
   [man 'Ricky]

   [woman 'Mary]
   [woman 'Martha]
   [woman 'Lucy]

   [likes 'Bob 'Mary]
   [likes 'John 'Martha]
   [likes 'Ricky 'Lucy]))

(def facts1 (-> facts0 (pldb/db-fact fun 'Lucy)))

Querying and testing:

(defn simple-query [db]
  (pldb/with-db db
    (log/run* [q]
      (log/fresh [x y]
        (fun y)
        (likes x y)
        (log/== q [x y])))))

;;logos.serial>(simple-query facts1)
;;([Ricky Lucy])

(freeze-to! facts1 "facts.lz4")
(def facts-thawed (thaw-from! "facts.lz4"))

;;logos.serial>(= facts1 facts-thawed)
;;logos.serial> (simple-query facts-thawed)
;;([Ricky Lucy])
Thanks.   I hadn't looked at that.   That will work.   

I also got it running with spit/slurp commands.  So, I don't know what I was doing before.  Something stupid probably.

Again, thanks for the answer.   Going to check out nippy now...
spit/slurp will work since the implementation details are map/record-based and they have readable representations.  Depending on the size of the thing you're serializing, and how often you're freezing/thawing, and other concerns like compression, I think nippy just ends up dominating in just about every case (except that spit/slurp are bundled already :) ).  That being said, poor folks serialization via spit/slurp is surprisingly useful.
Welcome to Clojure Q&A, where you can ask questions and receive answers from members of the Clojure community.