我在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
的链接,我们fail
else我们succeed
。
还要注意使用fresh
引入一个逻辑变量p
,它不是所需答案输出的一部分,因为我们只关心孤立的页面值。