Clojure核心逻辑:nafc和ground



我在Clojure的core.logic.中表示一个简单的数据库

有两个谓词:page(p(和link(p,q(。

page(p(表示在名为p 的wiki中存在页面

链接(p,q(表示页面p包含到页面q的链接。

我现在正试图查询这个数据库以查找

  • a(断开的链接(即页面p中的链接,没有页面q(,以及
  • b( 孤立页面(没有链接的页面(

我对这些查询的代码是:

(defn broken-links []
(pldb/with-db @facts
(logic/run* [p q]
(link p q)
(logic/nafc page q)
)))
(defn orphans []
(pldb/with-db @facts
(logic/run* [p q]
(logic/nafc link p q)
(page q)
)))

断开的链接按预期工作,但孤儿会给我一个符号列表。

我认为这与nafc的局限性有关。根据文件:

实验:否定作为失败约束。的所有参数目标c必须是地面。如果某个论点不是执行的基础将延迟此约束的。

这些都是"延迟"的,因为它们不是"地面"。

有人能解释一下地面在这里的真正含义吗。我知道它"没有自由变量",但我仍然不明白在这种情况下这意味着什么。

其次,我应该如何编写这个孤儿查询?

nafc的上下文中,非接地输入是通过给出非接地输出来处理的,因此要获得有意义的答案,您的输入"必须是接地的"。它不能否定涉及非接地值的约束。

例如,这个程序给出了q的所有可能值,其中q满足emptyo:

(run* [q]
(emptyo q))
;=> (())

如果我们要求q的所有可能值都不满足emptyo,我们得到的是:

(run* [q]
(nafc emptyo q))
;=> ((_0 :- (clojure.core.logic/nafc #object[clojure.core.logic$emptyo 0x212442c1 "clojure.core.logic$emptyo@212442c1"] _0)))

一个简化的短语是((_0 :- (nafc emptyo _0))),这意味着只有一个答案,但它可以是满足RHS约束的任何值。逻辑程序不能给我们基础值,因为它不知道所有可能的非空列表。

这里有一个完整的DB设置示例:

(pldb/db-rel page q)
(pldb/db-rel link p q)
(def facts
(pldb/db
[page 'a]
[page 'b]
[page 'z]
[link 'a 'b]
[link 'b 'c]))

和你的工作断链程序:

;; find links to non-pages
(pldb/with-db facts
(run* [p q]
(link p q)
(nafc page q)))
;=> ([b c])

以下是编写孤立页面程序的方法:

;; find pages without incoming links
(pldb/with-db facts
(run* [q]
(fresh [p]
(page q)
(conda
[(link p q) fail]
[succeed]))))
;=> (a z)

这里的否定用conda表示,形成一种if-else逻辑:if有一个到页面q的链接,我们failelse我们succeed

还要注意使用fresh引入一个逻辑变量p,它不是所需答案输出的一部分,因为我们只关心孤立的页面值。

最新更新