2012-03-15 10 views
11

Estoy modelando un árbol genealógico con core.logic. Me gustaría run* las consultas y hacer que devuelvan todos los resultados sin duplicación. Reemplazar todos defn con def tabled me da los resultados que espero (al menos por ahora), y sé que condu y onceo pueden reducir el número de resultados, pero no estoy seguro si alguno de ellos es la mejor manera de eliminar duplicados.Eliminando resultados duplicados al consultar un árbol genealógico con core.logic

Estoy particularmente preocupado por mi enfoque actual, ya que parece duplicar el trabajo para declarar tanto las relaciones como las funciones. Sé que algunas de mis relaciones son 'mutuamente recursivas' (mothero y womano se refieren entre sí), pero lo hice porque en el futuro podría agregar un nuevo (defrel mother*), lo que debería permitir inferir que una madre es a la vez madre y padre una mujer.

(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]))) 

Respuesta

5

No está seguro de qué es exactamente lo que usted está tratando de lograr, pero los objetivos (cosas que terminan en 'O') parece (como usted ha dicho) redundante y lo son. Además, no puede obtener parento para ejecutar con run* porque no hay restricciones en sus consultas. Intentará devolver una lista infinita de pares de padres y niños. Aquí hay algunas consultas de ejemplo usando sus relaciones:

;; 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]) 

Y puede seguir así por un tiempo. La programación lógica crea un lenguaje de consulta muy poderoso por sí solo, incluso cuando se usa solo con relaciones simples.

actualización: He aquí un ejemplo de brothero en el que el segundo argumento debe ser el hermano:

(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]) 

Como ves no me molesta para definir un objetivo parento ya que es redundante. Debe tener en cuenta que (!= a b) es necesario para no obtener pares que contengan a la misma persona dos veces y que haya una restricción en el padre para evitar doblar las respuestas. Obviamente, este ejemplo no funcionaría si no tiene el padre registrado o para un hombre que tiene hijos de varias mujeres.

+0

La razón por la que he definido las funciones parento, fathero, siblingso, etc. es que luego quiero usarlas como bloques de construcción para definir relaciones más grandes. Como primo sería más fácil de definir usando siblingso y parento. en lugar de restringirlo a solo padre *. Me gustaría terminar las funciones de compilación para cualquier tipo de relación, hermanos, tíos, primos segundo, antepasados, descendientes, relacionados, etc. Simplemente no sé cómo definirlos para que acepten nuevas relaciones como hermana * mientras también termina cuando se ejecuta con ejecución *. – WuHoUnited

+0

He actualizado mi respuesta para incluir un ejemplo de (versión simplificada) de 'brothero', ¡espero que esto lo ayude a lograr sus objetivos! ;-) –

+0

He hecho otro pequeño cambio en el último ejemplo, ya que no había necesidad de usar 'defne' en este caso. –

Cuestiones relacionadas