12

我正在用 core.logic 建模一个家谱。我想run*查询并让他们返回所有结果而不重复。将所有defn替换def tabled为我所期望的结果(至少现在是这样),我知道这一点condu并且onceo可以减少结果的数量,但我不确定其中任何一个是否是消除重复项的最佳方法。

我特别担心我目前的方法,因为声明关系和函数似乎是重复的工作。我知道我的一些关系是“相互递归的”(mothero并且相互womano引用),但我这样做是因为将来我可能会添加一个新的(defrel mother*),这应该可以推断出母亲既是父母又是女人。

(defrel man* person)
(defrel woman* person)
(defrel parent* child father)

(fact man* :Father)
(fact woman* :Mother)
(fact man* :Son)
(fact woman* :Daughter)
(fact parent* :Son :Father)
(fact parent* :Son :Mother)
(fact parent* :Daughter :Father)
(fact parent* :Daughter :Mother)

(defn mano [person]
(conde 
    [(man* person)]
    [(fresh [c]
        (fathero c person))]))

(defn womano [person]
(conde
    [(woman* person)]
    [(fresh [c]
        (mothero c person))]))

(defn parento [child person]
(conde
    [(parent* child person)]
    [(mothero child person)]
    [(fathero child person)]))

(defn fathero [child father]
(all
    (mano father)
    (parento child father)))

(defn mothero [child mother]
(all 
    (womano mother)
    (parento child mother)))

(defn siblingso [c1 c2 mother father]
    (all
        (mothero c1 mother)
        (mothero c2 mother)
        (fathero c1 father)
        (fathero c2 father)
        (!= c1 c2)))

(run 10 [q]
    (fresh [child parent]
        (parento child parent)
        (== q [child parent])))

(run 10 [q]
    (fresh [c1 c2 p1 p2]
        (siblingso c1 c2 p1 p2)
        (== q [c1 c2 p1 p2])))
4

2 回答 2

5

不确定您到底要达到什么目标,但目标(以“o”结尾的东西)似乎(如您所说)是多余的,而且确实如此。此外,您无法parento运行,run*因为您的查询没有限制。它将尝试返回子父对的无限列表。以下是一些使用您的关系的示例查询:

;; find all child-parent pairs
(run* [q] (fresh [c p] (parent* c p) (== q [c p])))
;=> ([:Daughter :Mother] [:Son :Mother] [:Daughter :Father] [:Son :Father])

;; find all child-father pairs
(run* [q] (fresh [c p] (parent* c p) (man* p) (== q [c p])))
;=> ([:Daughter :Father] [:Son :Father])

;; find all daughter-father pairs
(run* [q] (fresh [c p] (parent* c p) (man* p) (woman* c) (== q [c p])))
;=> ([:Daughter :Father])

;; some new facts
(fact parent* :grand-child :Son)
(fact parent* :great-grand-child :grand-child)

;; find all people who are grandparent
(run* [q] (fresh [c p gp] (parent* c p) (parent* p gp) (== q [gp])))
;=> ([:Mother] [:Father] [:Son])

你可以这样继续一段时间。即使仅与简单的关系一起使用,逻辑编程也可以自己制作一种非常强大的查询语言。

更新brothero:这是第二个参数应该是兄弟的示例:

(defn brothero [a b]
  (fresh [f]
    (!= a b)
    (parent* a f)
    (parent* b f)
    (man* f)
    (man* b))))

(run* [q] (fresh [a b] (brothero a b) (== q [a b])))
;=> ([:Daughter :Son])

如您所见,我懒得定义parento目标,因为它是多余的。您应该注意,(!= a b)不能两次获得包含同一个人的配对,并且对父母有一个限制,以防止答案加倍。显然,如果您没有记录父亲或有多个女人的孩子的男人,则此示例将不起作用。

于 2012-03-16T00:34:19.233 回答
0

如果你想使用递归关系,你可以使用这个扩展 https://github.com/niitsuma/Racket-miniKanren/tree/recursive

也许重写

walk walk* 统一发生检查

像这个扩展一样,也可以在 clojure 中启用递归关系

于 2013-07-09T20:33:06.513 回答