W jednym z wcześniejszych wpisów poruszałem temat definiowania relacji symetrycznych w języku Prolog. Rozwiązaniem problemu okazało się tam zdefiniowanie relacji pomocniczej, dzięki której pozbywaliśmy się nieskończonej pętli wywołań. Podobnie jest i w tym przypadku, bowiem i tu definiowanie takiej relacji w sposób „naiwny” i „naturalny” nie zdaje egzaminu. Rozważmy taki oto przykład, w którym szeregujemy kraje pod względem wielkości terytorium:
1 2 3 4 5 6 7 |
bigger(russia, canada). bigger(canada, china). bigger(china, usa). bigger(usa, brasil). bigger(brasil, australia). bigger(X,Z) :- bigger(X,Y), bigger(Y,Z). |
Chcielibyśmy, aby klauzula bigger
była relacją przechodnią. Jeśli Rosja jest większa od Kanady, a Kanada większa niż Chiny, to oznacza to, że Rosja jest większa od Chin. Dla ścisłości matematyczna definicja takiej relacji:
Oczywiście zadając zapytanie takie jak bigger(russia, china)
czy bigger(china, X)
w napisanym powyżej programie nie otrzymamy żadnej sensownej odpowiedzi, ale doprowadzimy do nieskończonej pętli wywołań. Przedstawia to poniższy obrazek:
Jak widać, kiedy Prolog dociera do Australii, która jest ostatnia w zdefiniowanym przez nas łańcuchu państw, pojawia się problem. Próbując zunifikować wyrażenie bigger(australia, Y)
za każdym razem dociera do naszej nieszczęsnej klauzuli opisującej przechodniość relacji.
Co należy zatem zrobić? Odseparować wiedzę (fakty) od reguł (relacji). Fakty zdefiniujmy używając np. klauzuli o nazwie bigger_fact
albo bigger_than
, a przechodniość przy pomocy klauzuli, której będziemy chcieli używać w naszych zapytaniach.
1 2 3 4 5 6 7 8 9 10 |
bigger_fact(russia, canada). bigger_fact(canada, china). bigger_fact(china, usa). bigger_fact(usa, brasil). bigger_fact(brasil, australia). bigger(X,Y) :- bigger_fact(X,Y). bigger(X,Z) :- bigger_fact(X,Y), bigger(Y,Z). |