Обратная цепочка Clojure для поиска фактов

#clojure #clojure-core.logic #clara-rule-engine

#clojure #clojure-core.logic #clara-механизм правил

Вопрос:

Мы используем систему правил с прямой цепочкой, в которой мы должны кормить систему данными, необходимыми для принятия решения. Я бы предпочел, чтобы система правил могла задавать вопросы, чтобы получить данные, необходимые для принятия решений. В Jess это кажется возможным с помощью волшебного префикса «need-«:

 (defrule create-member
    (need-member $?)
    =>
    (assert (member A B))) ; eg. DB call to check membership, if needed for goal finding.

(defrule rule-1
    (member ?A ?B)
    =>
    (printout t member crlf))
  

С помощью этого решения ненужные факты не извлекаются. Кроме того, значимость может быть использована, чтобы помочь избежать более дорогостоящего поиска фактов (например, удаленных вызовов), а также сохранить код СУХИМ

Хотя Jess, похоже, решает эту проблему, предпочтительнее решение Clojure без лицензии. Однако неясно, как это осуществить, например, с помощью clojure.logic. Клара использует прямую цепочку, которая кажется бесполезной, но, возможно, с генерацией правил возможен взлом, подобный Jess?

Действительно ищу пример выполнения аналогичного в Clojure.

Ответ №1:

Просто чтобы это было связано отсюда, кто-то ответил Джоэлу на этот самый вопрос в Ask Clojure: Спросите Clojure: Может ли core.logic задавать вопросы?

Ответ заключается в следующем:

Не будучи отличным пользователем 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
()
  

Я уверен, что есть способ сохранить факты, собранные в интерактивном режиме
(возможно, термин — таблица) или, в идеале, для обновления базы данных фактов
в режиме реального времени по мере продвижения поиска. Однако в настоящее время я не знаю.