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

+1 vote
in Clojure by

Can core.logic ask a question, ala prolog:

commits(Person, Crime) :-

format('is ~w ?', [commits(Person, Crime)]),

As seen on stackoverflow.

1 Answer

+1 vote
selected by
Best answer

Not being a great minikanren or core.logic user, I was able to coax out a little solution this way:

(ns logos.demo
  (:require [clojure.core.logic :as l]
            [clojure.core.logic.pldb :as pldb]))

;; guilty(X) :-
;; commits(X,Y),
;; crime(Y).
;; crime(murder).
;; crime(theft)

(pldb/db-rel person x)
(pldb/db-rel crime x)
(pldb/db-rel commits x y)

(def facts
  (pldb/db-facts pldb/empty-db
                 [person "bill"]
                 [crime :murder]
                 [crime :theft]
                 [commits "bill" :theft]))

(defn ask! [person act]
  (println  (str "Does " person " commit " act "?"))
  (-> (read-line)
      #{"y" "yes"}
      some? ))

(defn commitso
  [p act]
   [(person p) (commits p act)]
   [(l/project [p act]
             (l/==  (ask! p act) true))]))

(defn crimes [name]
  (->> (l/run-db* facts [p c]
                (l/== p name)
                (crime c)
                (commitso p c))
       (map second)))

If you evaluate it at the repl, you should get an interactive prompt if the name is not related to a known person:

logos.demo=> (crimes "bill")
logos.demo=> (crimes "tom")
Does tom commit :theft?  
Does tom commit :murder?
(:theft :murder)
logos.demo=> (crimes "tom")
Does tom commit :theft?
Does tom commit :murder?

I am sure there is a way to retain facts gathered interactively too (maybe the term is tabling), or ideally, to update the fact database in real time as the search progresses. I am currently unaware though.

I suppose logic doesn't have a way to prefer (similar to salience) one line of question over another, or maybe that can be addressed by ordering the statements. Thanks for this good start.