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