On Lisp -> Clojure: ProloG (pt. 1)

by fogus

; As always, I will post when the code is “complete”, but my progress can be followed on Github. Also, this post is executable, just copy and paste into a Clojure REPL.

(comment “

Posts in this series: ch. 2, ch. 2 redux, ch. 3, ch. 4, ch. 5, ProloG pt. 1

First, let me thank Stuart Halloway for picking up the On Lisp -> Clojure port where I left off. I do not know if that was intentional, but in any case it makes for nice reading to start with my first 5 chapters and then transition right into Mr. Halloway’s posts (which are much higher quality IMO).


; One of my favorite parts from On Lisp is his implementation of an embedded Prolog interpreter based on a simple database and inference system. My main goal for starting the On Lisp -> Clojure series was to eventually have this embedded Prolog system to use in my own applications. I will start out by just talking about a few preliminary structures and functions and then expand on them in future installments.


;; The original Lisp make-hash-table function works on a
;; cons-cell structure, however Clojure provides a persistent
;; hash structure instead.  I am not going to port the Common
;; Lisp function to Clojure, but instead will modify the Prolog
;; implementation to fit a more idiomatic Clojure approach.
(defn makedb []

(def *defaultdb* (ref (makedb)))

(defn cleardb
  "Takes a db and clears it"
  ([] (cleardb *defaultdb*))
  ([db] (dosync (refset db nil))))

(defn dbquery
  "Takes a db and a key and returns the mapped val"
  ([key] (dbquery *defaultdb* key))
  ([db key] (get @db key)))

;; db-push in Clojure is a bit trickier since it will be working
;; on a referenced persistent hash map.  This version is larger
;; than the On Lisp version do to the fact that the database
;; being queried is an in-transaction value.  
(defn dbpush
  "Stores a value in a the db"
  ([key val] (dbpush *defaultdb* key val))
  ([db key val]
      (commute db
               (fn [thedb key val]
                 (assoc thedb key (cons val (get thedb key))))

;; fact is almost a direct translation save for minor syntax diffs
(defmacro fact
  [pred & args]
     (dbpush '~pred '~args)

(defn testpt1 []
  (fact painter reynolds joshua english)
  (fact painter canale antonio venetian)
  (dbquery 'painter))


; There is definitely some room for improvement (suggestions/criticisms always welcome), but these initial functions work the same as the On Lisp originals, so that’s all for now. I’ll come back later for more.