由于我不是一个很棒的 minikanren 或 core.logic 用户,我这样得到了一点解决方法
(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)
clojure.string/trim
clojure.string/lower-case
#{"y" "yes"}
some? ))
(defn commitso
[p act]
(l/conda
[(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)))
如果您在 repl 中评估它,如果在名称与已知人物不相关的情况下,您应该会得到一个交互式提示
logos.demo=> (crimes "bill")
(:theft)
logos.demo=> (crimes "tom")
Does tom commit :theft?
y
Does tom commit :murder?
y
(:theft :murder)
logos.demo=> (crimes "tom")
Does tom commit :theft?
n
Does tom commit :murder?
n
()
我相信也存在一种方法可以保留通过交互收集的事实(或许术语是 tabling),或者理想情况下,在搜索过程中实时更新事实数据库。但我目前还不了解。