Clojure core.logic。我可以在事实和规则中使用复杂的数据结构吗?

Clojure core.logic. Can I use complex data-structures in facts and rules?

我正在努力掌握 core.logic。

我可以在事实和规则中使用复杂的数据结构吗?

例如,我正在尝试这样做:

(pldb/db-rel test a)

(defn is-wibble? [a] (= true (:wibble a)))

(def facts
  (pldb/db
   [test {:name "x" :wibble true}]
   [test {:name "y" :wibble false}]
   [test {:name "z" :wibble true}]))

(defn -main [& args]
  (doseq [x
          (pldb/with-db facts
            (run* [q]
              (is-wibble? q)))]
    (println x))))

但是它抛出一个错误:

Caused by: java.lang.ClassCastException: java.base/java.lang.Boolean cannot be cast to clojure.lang.IFn
    at clojure.core.logic.Substitutions.bind(logic.clj:425)
    at polvo.core$_main$fn__377$fn__378$fn__379$_inc__380.invoke(core.clj:223)

实际上在第

(is-wibble? q)

尝试将规则创建为普通函数我错了吗?还是把复杂的数据变成事实?

您可以在您的 db 中检查复杂的数据结构,这里唯一缺少的部分是在您的 is-wibble? 谓词中您将收到一个 逻辑变量 而不是实际的具体值。

core.logic 中有一个 pred 目标,它将 project 一个 lvar,因此您可以检查它的值。我重命名了目标以匹配典型的目标名称。 pred 接受一个 lvar 和一些将接收 lvar 的值的函数,并且如果该谓词函数 returns truth-y.

pred 目标成功
(defn wibbleo [a] (pred a :wibble))

或者您可以使用原始谓词这样定义它:

(defn wibbleo [a] (pred a is-wibble?))    

请注意,您还需要将 db-rel 作为目标 (test q),然后您的程序应该可以运行:

(pldb/with-db facts
  (run* [q]
    (test q)
    (wibbleo q)))
=> ({:name "x", :wibble true} {:name "z", :wibble true})