我正在使用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])))
答案 0 :(得分: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)
需要两次不能包含同一个人的对,并且父母有一个约束来防止答案加倍。显然,如果你没有记录父亲,或者有一个有多个女人子女的男人,这个例子就行不通了。
答案 1 :(得分:0)
如果要使用递归关系,可以使用此扩展名 https://github.com/niitsuma/Racket-miniKanren/tree/recursive
也许重写
步行步行*统一发生 - 检查
喜欢这个扩展, 还可以在clojure中启用递归关系