Устранение дублирующихся результатов при запросе генеалогического дерева с core.logic - PullRequest
11 голосов
/ 15 марта 2012

Я моделирую генеалогическое дерево с помощью 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])))

Ответы [ 2 ]

5 голосов
/ 16 марта 2012

Не уверен, что именно вы пытаетесь достичь, но цели (заканчивающиеся на '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) требуется, чтобы не получать пары, содержащие одного и того же человека дважды, и что существует ограничение для родителя, чтобы не удваивать ответы.Очевидно, этот пример не сработает, если у вас не будет записи отца или мужчины, у которого есть дети от нескольких женщин.

0 голосов
/ 10 июля 2013

Если вы хотите использовать рекурсивное отношение, вы можете использовать это расширение https://github.com/niitsuma/Racket-miniKanren/tree/recursive

Может быть, переписать

прогулка прогулка * унификация происходит-проверка

как это расширение, также позволяет рекурсивное отношение в clojure

...