2013-03-16 19 views
9

Czytałem odpowiedź na this pytanieCo oznacza symbol "-" w Prologu podczas pracy z listami?

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

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

Powyższy kod używa składnia List-List. W pewnym stopniu rozumiem, co się dzieje, ale chcę wiedzieć, co dokładnie robi tutaj symbol/predykat "-". Czy jest to specyficzne dla SWI?

+0

@ p.s.w.g: Dlaczego zagłosowałeś, aby to zamknąć? – false

+1

'' -'' tutaj nie jest predykatem, jest "funktorem" - nazwą złożonej struktury. Na przykład. w 'f (1,2)', 'f' jest funktorem złożonego terminu z dwoma argumentami. (jeśli szukasz, szukaj "Funktora Prologa", po prostu "funktor" pokaże ci mnóstwo niespokrewnionych rzeczy). –

+0

Masz całkowitą rację - niestety, nie pozwolę mi usunąć flagi. Skasowałem jednak mój komentarz. –

Odpowiedz

6

(-)/2 reprezentuje różnicę wymienia jest raczej rzadkością konwencji. W starszych książkach był również używany inny operator (\)/2.

Wielu woli używać zamiast tego dwóch oddzielnych argumentów. Istnieje kilka korzyści w porównaniu z korzystaniem z operatora:

  1. Predykatu nie można przypadkowo użyć z niepotwierdzoną zmienną dla argumentu. Pomyśl o wywołaniu q(A, X) zamiast q(A, X-[]).

  2. Wykonanie jest nawet trochę bardziej wydajne, gdy używa się dwóch argumentów. Wiele systemów, takich jak SWI, musi dynamicznie tworzyć każdą strukturę (-)/2.

Niemniej jednak, istnieje również inny sposób na wykorzystanie list różnica, która jest często mniej podatne na błędy: Można użyć do tego celu.

W rzeczywistości są dwa błędy w programie, z których jeden jest spowodowany sposobem obsługi listy różnic. Innym błędem jest to, że program nie obsługuje końca pliku. Byłoby lepiej użyć end_of_file zamiast end. Ale to jest powierzchowne, co wcześniej czy później byś odkrył.

Drugi, bardziej subtelny błąd wynika z interakcji między listami różnic i cięciem. Nie jestem wielkim fanem cięć, ale spójrzmy na tę zasadę. Cięcie cięć po tym, jak wszystko na lewą stronę zostało wykonane.

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

Pierwszy argument to atom end_of_file. Ponieważ używamy q/2 tylko z wynikiem read/1 jako pierwszego argumentu, może to być tylko porównanie. Jesteśmy na końcu pliku (lub strumienia). Następnie jednak są dalsze rzeczy, które muszą się utrzymywać. I tylko wtedy, gdy ci się powiodą, rozcięcie zostanie wykonane: Drugi argument musi być (-)/2 (no dobrze, we wszystkich miejscach na jego miejscu znajduje się minus). A następnie: dwa argumenty (-)/2 muszą być takie same (należy ujednolicić). Czemu? Jesteśmy na końcu pliku, ale jeśli te argumenty nie zostaną zunifikowane, druga zasada zostanie wypróbowana.

Kiedy to się dzieje?Tutaj jest taki paskudny przypadek:

p([X,Y,Z]). 

I wystarczy wpisać jedną stałą, powiedzmy my_constant. a następnie naciśnij cntrl-d lub cntrl + z. Co powinien zrobić w takim przypadku p/1? W idealnej sytuacji zakończyłoby się to niepowodzeniem po zakończeniu wprowadzania danych. Jednak będzie czekać na dalsze wprowadzanie.

Powodem jest niewłaściwe umieszczenie cięcia. Mówimy, że p/1 nie jest niezłomny. Jest to częsty błąd w programach Prolog. Mogę tylko zalecić ograniczenie stosowania cięć i przyjęcie DCG. Z DCGs, to nie może się zdarzyć:

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

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

z DCGs, cięcie jest wykonywane niezależnie od argumentu p/1.

+0

'q (end_of_file, Z): -!, Z = X-X. q (koniec, Z): -!, Z = X-X ". Tylko mówię. Myślę, że "Clause and Effect" używa funktora '' -''', IIRC. –

+0

@WillNess: Znasz konkretną bibliotekę w systemie Prolog, która używa tej konwencji? – false

+0

Nie, nic takiego nie powiedziałem. "Cause and Effect" to chyba 80-ta książka. –