2012-03-15 15 views
11

Sto modellando un albero genealogico con core.logic. Vorrei rispondere alle domande con run* e restituirle tutti i risultati senza duplicare. Sostituire tutto defn con def tabled mi dà i risultati che mi aspetto (almeno per ora) e so che condu e onceo possono ridurre il numero di risultati, ma non sono sicuro se uno di questi sia il modo migliore per eliminare i duplicati.Eliminazione dei risultati duplicati durante l'interrogazione di un albero genealogico con core.logic

Sono particolarmente preoccupato per il mio approccio attuale perché sembra un lavoro duplicato per dichiarare sia le relazioni che le funzioni. So che alcune delle mie relazioni sono "reciprocamente ricorsive" (mothero e womano di riferimento l'un l'altro), ma l'ho fatto perché in futuro potrei aggiungere un nuovo (defrel mother*), che dovrebbe consentire di dedurre che una madre è sia un genitore che una donna

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

risposta

5

Non sei sicuro di cosa esattamente si sta cercando di ottenere, ma gli obiettivi (roba che terminano in 'o') sembra (come hai detto) ridondanti e lo sono. Inoltre, non è possibile ottenere parento per l'esecuzione con run* perché non ci sono vincoli sulle query. Proverà a restituire una lista infinita di coppie figlio-genitore. Ecco alcune query di esempio che utilizzano le tue relazioni:

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

E puoi continuare così per un po '. La programmazione logica rende un linguaggio di query molto potente da solo, anche se utilizzato solo con relazioni semplici.

Aggiornamento: Ecco un esempio di brothero in cui il secondo argomento dovrebbe essere il fratello:

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

Come vedete non si preoccupano di definire un obiettivo parento quanto è ridondante. Si noti che è necessario (!= a b) per non ottenere coppie contenenti la stessa persona due volte e che esiste un vincolo sul genitore per impedire il raddoppio delle risposte. Ovviamente questo esempio non funzionerebbe se non si registra il padre o per un uomo che ha figli da più donne.

+0

Il motivo per cui ho definito le funzioni parento, fathero, siblingso, ecc. è che poi voglio usarli come elementi costitutivi per definire relazioni più grandi. Come cousinso sarebbe più facile definire usando siblingso e parento. invece di limitarlo a solo genitore *. Mi piacerebbe finire per costruire funzioni per qualsiasi tipo di relazione, fratelli, zii, 2 ° cugino, antenati, discendenti, imparentati, ecc. Io non so come definire questi in modo che accetterebbero nuove relazioni come sister * mentre termina anche quando viene eseguito con run *. – WuHoUnited

+0

Ho aggiornato la mia risposta per includere un esempio di (versione semplificata) di 'brothero', spero che questo ti aiuti a raggiungere i tuoi obiettivi! ;-) –

+0

Ho fatto un'altra piccola modifica nell'ultimo esempio, in quanto non è stato necessario utilizzare 'defne' in questo caso. –

Problemi correlati