2012-03-15 42 views
11

我正在使用core.logic建模家族树。我想run*的查询并让他们返回所有结果而没有重复。用def tabled替换所有defn给我我期望的结果(至少现在),并且我知道conduonceo可以减少结果的数量,但我不确定这些是否是消除重复的最佳方法。使用core.logic查询家族树时消除重复结果

我特别担心我目前的方法,因为它似乎是重复的工作来声明关系和功能。我知道我的一些关系是'相互递归的'(motherowomano互相引用),但我这样做是因为将来我可能会添加一个新的(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]))) 

回答

5

不知道你想什么来实现的,但目标(东西在“O”结尾),似乎(如你所说)多余的,他们是。此外,由于您的查询没有限制,因此无法使用run*运行parento。它将尝试返回无限的子对父对的列表。这里有一些使用你的关系的例子查询:

;; 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)是不需要两次包含同一个人的对,并且父母有一个约束,以防止两倍的答案。很显然,如果你没有记录父亲或者有一个有多个女孩子的男人,这个例子就不适用了。

+0

我定义函数parento,fathero,siblingso等的原因是我想用它们作为构建块来定义更大的关系。就像cousinso一样,使用siblingso和parento会更容易定义。而不是仅限于父*。我想最终为任何类型的关系,兄弟,叔叔,表弟,祖先,后代,相关等构建函数。我只是不知道如何定义这些关系,以便他们将接受新的关系姊妹*,同时在运行时也终止*。 – WuHoUnited 2012-03-16 02:59:49

+0

我已经更新了我的答案,以包含brothero(简化版)的示例,希望这可以帮助您实现目标! ;-) – 2012-03-16 04:27:11

+0

我在最后一个例子中做了一个小改动,因为在这种情况下不需要使用'defne'。 – 2012-03-16 20:48:19