2013-11-24 19 views
6

Sono nuovo al prolog e sto sperimentando come arrestarlo dopo aver trovato una risposta. Sto usando questo codice:Fai in modo che Prolog restituisca una soluzione e smetta di mostrare l'opzione di query

member1(L,[L|_]).      
member1(L,[_|RS]) :- member1(L,RS),!.  

Il risultato è: "true"

| ?- member1(3,[3,2,3]). 

true ? a 

yes 

Mi sono perso quanto a come avrei potuto ottenere Prolog per interrompere la stampa e basta stampare "sì" invece. Ho provato a usare if/else construct e la funzione di formattazione, ma stampa ancora "true?". Qualche idea?

+0

Vuoi solo una risposta? uno 'vero'? Τrue significa che 3 * è * un membro della lista [3,2,3]. Il secondo vero è che la query l'ha trovata di nuovo nell'elenco. 'member1 (2, [3,2,3]).' ti darebbe solo una vera. – Shevliaskovic

+0

Se premi Invio dopo il primo vero (invece di ';'), si fermerebbe il backtracking – Shevliaskovic

risposta

3

Stai tagliando il posto sbagliato. Tagliare dopo la condizione di base, che dice: "una volta che la base è soddisfatta, non tornare indietro più":

member1(L,[L|_]) :- !.     
member1(L,[_|RS]) :- member1(L,RS).  

Se-allora non lavoro per me, forse si implementato diverso? (Su SWI-prolog)

member1(X,[Y|RS]) :- 
    (X = Y   -> true 
    ; member1(X,RS) -> true 
    ; false 
    ) . 

Swi ha anche il predicato once/1.

modificato per tenere conto dell'errore indicato da false.

+0

La tua versione if-then-else ha successo due volte ... – false

+0

@false Ah! Avevo trascurato la situazione ovvia in cui il primissimo elemento corrisponde. Risolto ora. Grazie per la segnalazione. –

2

Dall'output mostrato, presumo che si stia utilizzando GNU Prolog. Ma, prima di tutto una nota importante:

Il taglio che hai inserito non taglia come tu lo intendi! In realtà, non impedisce nemmeno che ci sia una sola risposta. Qui è la prova per questo:

| ?- member1(X,[1,2,3]). 

X = 1 ? ; 

X = 2 

yes 

in modo da avere ancora due risposte. Come regola generale: un taglio dopo un obiettivo ricorsivo spesso fa cose inaspettate.

Se si desidera ottenere esattamente la prima risposta, è sufficiente pronunciare once(member(X,[1,2,3])). Anche lo once/1 è effettivamente un taglio, ma completamente travestito. È addomesticato per fare esattamente una cosa. Sì, puoi inserire anche i tagli in regole ricorsive, ma per un principiante, meglio lasciarlo a una lezione successiva.

Dietro tutto questo c'è un altro punto, che è meno visibile: il guscio di GNU Prolog ti chiederà ulteriori soluzioni se vede un'alternativa aperta (gergo: punto di scelta). Così, quando GNU si chiede di più, si sa che una parte deve ancora essere esplorata, ma non v'è alcuna garanzia che v'è in realtà un'altra risposta:

?- member(1-X,[1-a,2-b,3-c]). 

X = a ? ; 

no 

Qui, il primo livello vede un ChoicePoint aperto e chiede quindi se vuoi esplorare ulteriormente la query. Ahimè, questa ricerca è in vena ...