Clojure core.logic:nafc 和地面

Clojure core.logic : nafc and ground

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

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

page(p) 表示在名为 p

的 wiki 中存在的页面

link(p,q)表示p页包含一个link到q页

我现在正在尝试查询此数据库以查找

我的这些查询代码是这样的:

(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)
      )))

broken-links 按预期工作,但孤儿给了我一个列表:- 符号。

我假设这与 nafc 的限制有关。根据文档:

EXPERIMENTAL: negation as failure constraint. All arguments to the goal c must be ground. If some argument is not ground the execution of this constraint will be delayed.

而这些是 "delayed" 因为它们不是 "ground"。

谁能解释一下地面在这里的真正含义。我知道它是 "has no free variables",但我仍然不太明白在这种情况下这意味着什么。

其次,这个孤儿查询应该怎么写?

nafc 的上下文中,非地面输入通过提供非地面输出来处理,因此要获得有意义的答案,您的输入 "must be ground." 它不能否定涉及非地面值的约束.

例如,这个程序给出了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约束的值。逻辑程序无法为我们提供基础值,因为它不知道所有可能的非空列表。

为了完整性,这里有一个示例数据库设置:

(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]))

你的工作坏了-link程序:

;; 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有一个link 到第 q 页,我们 fail else 我们 succeed.

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