2013-03-16 26 views
9

Stavo leggendo la risposta alla domanda this,Che cosa significa il simbolo "-" in Prolog quando si tratta di elenchi?

p(X) :- read(A), q(A,X-[]). 

q(end,X-X) :- !.  
q(A,[A|X]-Y) :- read(B), q(B,X-Y). 

Il codice sopra usa la sintassi List-List. In qualche modo capisco cosa sta succedendo, ma voglio sapere che cosa esattamente fa qui il simbolo/predicato "-". Inoltre, questo SWI è specifico?

+0

@ p.s.w.g: Perché hai votato per chiudere questo? – false

+1

''-'' qui non è un predicato, è un" functor "- nome di una struttura composta. Per esempio. in 'f (1,2)', 'f' è un funtore di un termine composto con due argomenti. (se cerchi, cerca "Prolog functor", solo "functor" ti mostrerà una tonnellata di cose non correlate). –

+0

Hai perfettamente ragione - sfortunatamente, non mi permette di rimuovere la bandiera. Ho cancellato il mio commento, comunque. –

risposta

6

La (-)/2 per rappresentare differenza liste è una convenzione piuttosto rara. Nei libri più vecchi veniva utilizzato anche un altro operatore (\)/2.

Molti preferiscono utilizzare due argomenti separati invece. Ci sono diversi vantaggi rispetto all'utilizzo di un operatore:

  1. Il predicato non può accidentalmente essere utilizzato con una variabile istanziato per l'argomento. Pensa di chiamare q(A, X) al posto di q(A, X-[]).

  2. L'esecuzione è anche un po 'più efficiente quando si utilizzano due argomenti. Molti sistemi, come SWI, devono creare dinamicamente ciascuna struttura (-)/2.

Tuttavia, c'è anche un altro modo di utilizzare gli elenchi di differenza, che è spesso meno soggetto a errori: Si potrebbe utilizzare una per questo scopo.

In realtà, ci sono due errori nel programma, uno dei quali è causato dal modo in cui viene gestito l'elenco delle differenze. L'altro errore è che il programma non gestisce la fine del file. Sarebbe meglio usare end_of_file al posto di end. Ma questa è una cosa superficiale che ti saresti trovato prima o poi.

L'altro, più sottile errore è dovuto all'interazione tra liste di differenza e il taglio. Non sono un grande fan dei tagli, ma esaminiamo questa regola. Un taglio taglia dopo che tutto al suo lato sinistro è stato eseguito.

q(end_of_file,X-X) :- !. 

Il primo argomento è l'atomo end_of_file. Dato che stiamo usando q/2 solo con il risultato di read/1 come primo argomento, questo può essere solo un confronto. Quindi siamo alla fine del file (o stream). Quindi, tuttavia, ci sono altre cose che devono essere mantenute. E solo se anche questi riescono, verrà eseguito il taglio: Il secondo argomento deve essere un (-)/2 (ok, in tutti i punti c'è un meno al suo posto). E poi: i due argomenti di (-)/2 devono essere gli stessi (deve unificare). Perché? Siamo alla fine del file, ma se quegli argomenti non si uniscono, verrà tentata l'altra regola.

Quando succede questo?Ecco un caso così brutto:

p([X,Y,Z]). 

E sufficiente inserire una sola costante, dicono my_constant. quindi premere Cntrl-d o Cntrl + z. Cosa dovrebbe fare p/1 in questo caso? Idealmente, fallirebbe dopo aver finito l'input. Tuttavia, aspetterà ulteriori input.

Il motivo è l'errata collocazione del taglio. Diciamo che p/1 non è steadfast. Questo è un errore comune nei programmi Prolog. Posso solo raccomandare di ridurre l'uso di tagli e l'adozione di DCG. Con DCGs, questo non può accadere:

p2(X) :- read(A), phrase(q2(A),X). 

q2(end_of_file) --> !. 
q2(A) --> [A], {read(B)}, q2(B). 

Con DCGs, il taglio viene eseguito indipendentemente dal motivo di p/1.

+0

'q (end_of_file, Z): -!, Z = X-X. q (fine, Z): -!, Z = X-X'. Sto solo dicendo Penso che "Clause and Effect" usi il functor ''-'', IIRC. –

+0

@WillNess: conosci una libreria concreta in un sistema Prolog che utilizza questa convenzione? – false

+0

no, non ho detto niente del genere. "Cause and Effect" è un libro degli anni '80, credo. –