2012-03-15 3 views
11

core.logic을 사용하여 패밀리 트리를 모델링했습니다. run*에 쿼리를 입력하고 의 모든 결과를없이 반환하도록하고 싶습니다. defndef tabled으로 바꾸면 나는 (적어도 현재는) 기대하는 결과를 얻었으며, 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]) 

그리고 잠시 동안 계속 진행할 수 있습니다. 논리 프로그래밍은 단순한 관계에서만 사용되는 경우에도 매우 강력한 쿼리 언어를 만듭니다.

업데이트 : 여기에 2 번째의 인수가 형제해야 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 등의 함수를 정의한 이유는 더 큰 관계를 정의하는 빌딩 블록으로 사용하기 위해서입니다. 사촌과 마찬가지로 형제와 부모를 사용하여 정의하는 것이 쉬울 것입니다. 그냥 부모로 제한하는 대신 *. 형제, 삼촌, 두 번째 사촌, 조상, 자손, 관계형 등 모든 유형의 관계 함수를 구축하고 싶습니다. 이러한 관계를 정의하는 방법을 알지 못해서 다음과 같은 새로운 관계를 받아 들일 수 없습니다. 자매 * 또한 run *으로 달릴 때 종료됩니다. – WuHoUnited

+0

'brothero'의 (단순화 된 버전) 예제를 포함하도록 답변을 업데이트했습니다. 목표 달성에 도움이되기를 바랍니다. ;-) –

+0

이 예제에서는'defne'을 사용할 필요가 없으므로 마지막 예제에서 약간의 변경을했습니다. –