PROLOG z BLISKA Przygotowali: Konrad Daniszewski, Adam Kuliński, Konrad Poszwiński, Arkadiusz Trzciński
Wstęp Prolog zawiera mechanizmy pozwalające na strukturyzację danych oraz strukturyzację prób uwzględniania celów. Strukturyzacja danych związana jest ze znajomością składni używanej do zapisu danych.
Składnia Programy Prolog składają się z termów. Term to stała, zmienna lub struktura. Wszystkie rodzaje termów były pokazane w pierwszej prezentacji z Prologa, tylko nie znaliśmy tych nazw. Każdy term zapisywany jest jako ciąg znaków; znaki podzielono na cztery następujące kategorie: Wielkie litery: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Małe litery: a b c d e f g h i j k l m n o p q r s t u v w x y z Cyfry: 0 1 2 3 4 5 6 7 8 9 Znaki specjalne: + - * / \ ~ ^ < > : . ? @ # $ & Niektóre znaki specjalne poznamy później przy okazji. Tak czy siak, każdy rodzaj termu: stała, zmienna czy struktura, rządzi się innymi zasadami tworzenia jej nazwy ze znaków.
STAŁE Stałą nazywamy konkretne obiekty lub relacje. Istnieją dwa rodzaje stałych: atomy i liczby. Przykład: malwinka, grzesiu, posiada, zjada, sniadanie, samochod
STAŁE Atomy składają się z: • symboli, np. ?- lub :- , • liter, cyfr znaku podkreślenia (zaczynamy zawsze małą literą), • dowolnych znaków, jeśli ujęte są w pojedynczy cudzysłów. Liczby zapisujemy w takiej postaci: -17, 23, 99.9 (ważne!) , 123e-3
ZMIENNE Zmienne mają postać atomu złożonego z liter, cyfr lub znaku podkreślenia z zastrzeżeniem, że pierwszym znakiem musi być duża litera. Czasem interesuje nas tylko czy coś jest prawdą, ale zupełnie nie interesuje nas co. Czy ktoś lubi Grzesia? W takich sytuacjach możemy użyć zmiennej anonimowej zapisywanej jako jeden znak podkreślenia. ?- lubi(_,grzesiu).
STRUKTURA Struktura, inaczej term złożony, to obiekt złożony z innych obiektów. posiada(arek,auto). posiada(konrad,auto).
Struktura - przykłady posiada(arek,auto(nissan,almera)). posiada(konrad,auto(fiat,punto)). ?- posiada(X,auto(nissan,Y)). X = arek Y = almera ;
OPERATORY Zapis a-b*c to inna forma zapisu -(a,*(b,c)). Operator arytmetyczny nie powoduje wykonania jakichkolwiek obliczeń. 1+2 to nie jest to samo co 3 1+2 to inny zapis termu +(1,2) Kiedy własny operator lubi(malwinka,grzesia). malwinka lubi grzesia.
Własny Operator Operator jest atomem wiążącym kilka operandów, podobnie jak struktura, z tym wyjątkiem, że możemy zapisać go także w jednej z następujących postaci: • prefixowej, np. +(a,*(b,c)), • postfixowej, np. x!, • infixowej, np. 1*2. Definiując nowy operator, oprócz zdecydowania się na jedną z wcześniej opisanych postaci, ustalić musimy jego priorytet i łączność • priorytet: od 1 do 1200 (im mniej tym większy) • łączność: lewo- lub prawostronna (1-2-3 interpretowane jest jako ((1-2)-3) ponieważ - jest operatorem lewostronnie łącznym); łączność definiujemy za pomocą jednego z atomów: xf, yf, xfx, xfy, yfx, fx lub fy.
Własny Operator xf postfix (ang. non-associative) yf postfix lewostronny xfx infix n-a xfy infix prawostronny yfx infix lewostronny fx prefix n-a fy prefix prawostronny lubi(malwinka,grzesia). ?- [p1]. % p1 compiled 0.00 sec, 852 bytes Yes ?- lubi(malwinka,grzesia). Yes ?- malwinka lubi grzesia. ERROR: Syntax error: Operator expected ERROR: malwinka ERROR: ** here ** ERROR: lubi grzesia . ?- op(500, xfx, lubi). Yes ?- malwinka lubi grzesia.
Własny Operator ?- X is 2+3*5. X = 17 Yes ?- op(100,yfx,+). Yes ?- X is 2+3*5. X = 25 Yes ?-
ARYTMETYCZNE I LOGICZNE PREDYKATY SYSTEMOWE Język prolog posiada wsparcie do wykonywania prostych operacji arytmetycznych przy pomocy wbudowanych predykatów. Predykaty te nazywamy systemowymi. Pomimo pozornego podobieństwa do reszty predykatów, te są zaszyte bezpośrednio w kodzie środowiska, przez co działają szybciej i bardziej efektywnie niż predykaty napisane w czystym Prologu. W sytuacjach gdy mamy wybór pomiędzy predykatami wbudowanymi, a predykatami dodanymi warto wybierać predykaty wbudowane.
ARYTMETYCZNE I LOGICZNE PREDYKATY SYSTEMOWE Możemy zapisać następujące zdanie: (X is 1+2). w konsekwencji czego zostanie wykonanych tutaj kilka czynnosci: • zostanie wyliczona wartość wyrażenia 1+2, co doprowadzi nasze zapytanie do postaci X is 3 • is zostanie zinterpretowane jako podstawienie X:=3 • zostanie zwrócona wartość Yes informaująca o tym, że X i 3 mają teraz taką samą wartość.
ARYTMETYCZNE I LOGICZNE PREDYKATY SYSTEMOWE Jeśli napiszemy 3 is 1+2 wówczas is nie zadziała jako „operator” przypisania a spowoduje jedynie wykonanie porównania wartości z wyrażeniem. Zwróconą wartością będzie Yes. Jeśli napiszemy 1+2 is 1+2 wówczas zwrócona zostanie wartość No. Wynika to z faktu, że oba argumenty są wyrażeniami. Wyrażenie z prawej strony zostanie obliczone dając w wyniku liczbę 3. Wyrażenie z lewej strony pozostanie bez zmian, przez co nie będzie reprezentowane przez wartość 3.
ARYTMETYCZNE I LOGICZNE PREDYKATY SYSTEMOWE Do porównywania zamiast is możemy używać także operatora =:=, który w odróżnieniu od is pozwala na umieszczenie wyrażeń arytmetycznych w miejscu obydwu swoich argumentów. Możemy wiec napisać: (3+2 =:= 4+1). co zostanie poprawnie zinterpretowane i zwróci wartość ’Yes’.
ARYTMETYCZNE I LOGICZNE PREDYKATY SYSTEMOWE Prolog udostępnia także inne predykaty wyglądające jak operatory służące do porównywania wyrażeń arytmetycznych. Są nimi: • mniejszy < • większy > • mniejszy równy =< • większy równy >= Mogą one przyjmować wyrażenia arytmetyczne zarówno w pierwszym jak i drugim argumencie. W związku z tym da się wyliczyć wartość zapytań takich jak: (1+2 < 2+3). (1+2*3 >= 3+3). (1 < 4). (N < N+1). a jeśli wartości X, Y i Z są określone można również zapisać i wyliczyć (X >= Y+Z). (X+1 < Y*2+X).
SPEŁNIANIE CELÓW Prolog realizuje zadania w odpowiedzi na zapytania programisty. Zapytanie to koniunkcja celów, które mają być spełnione. W prologu do spełniania celów używa się klauzuli. Fakt może spowodować, że cel będzie spełniony od razu, zaś reguła pozwala zadanie spełnić stopniowo, przez spełnienie koniunkcji jej podcelów. Klauzuli używamy jedynie wtedy, gdy pasuje do spełnionego celu. Jeśli celu nie można spełnić, uruchamiane jest nawracanie. Nawracanie polega na przeglądaniu dotąd zrealizowanego programu i próbie ponownego spełnienia celów przez znalezienie ich alternatywnych rozwiązań.
UDANE SPEŁNIENIE KONIUNKCJI CELÓW Prolog stara się spełnić cele koniunkcji niezależnie od tego czy występują one w treści reguły, czy w zapytaniu. Odbywa się to w kolejności ich występowania, od lewej do prawej. Oznacza to, że Prolog nie stara się spełnić celu, póki nie zostanie spełniony jego lewy sąsiad. Kiedy cel zostaje spełniony, Prolog stara się spełnić jego prawego sąsiada. kobieta(maria). rodzic(C,M,F) :- matka(C,M), ojciec(C,F). matka(jan,anna). matka(maria,anna). ojciec(maria,ferdynand). ojciec(jan,ferdynand). ?- kobieta(maria), rodzic(maria,M,F), rodzic(jan,M,F).
UDANE SPEŁNIENIE KONIUNKCJI CELÓW Zwróćmy uwagę, że miejsce w zmiennych M i F używane są już ich wartości. Spełnienie drugiego celu obejmuje przeszukanie bazy danych w celu znalezienia unifikowanej klauzuli, następnie oznaczenie tego miejsca w bazie danych i spełnienie ewentualnych podcelów.
Cele i nawracanie Kiedy któryś cel zawodzi (z powodu sprawdzania alternatywnej klauzuli już raz uzgodnionego celu lub użycia przez użytkownika średnika), „przepływ spełniania” jest przekazywany z powrotem drogą, którą do danego miejsce doszedł. Następuje powrót przez punkty, które już raz były opuszczone, w celu znalezienia alternatywnych rozwiązań. Kiedy następuje powrót do miejsca klauzuli, Prolog stara się do danego celu znaleźć klauzule alternatywną. Jeżeli znalezione zostanie inne możliwe dopasowanie, oznaczane jest nowe miejsce i przetwarzanie jest kontynuowane. Prolog będzie się starał spełnić wszystkie cele, nawet jeżeli już były badane.
Cele i nawracanie Kiedy cel zawodzi, następuje powrót do poprzedniego. Nadrzędnego. Cofanie się trwa tak długo, aż zostanie znaleziony znacznik w bazie danych. Wszystkie zmienne, które znaleziono w celu cofania się, znów są nieukonkretnione. Prolog szuka w bazie danych klauzul zza znacznika. Jeśli taka klauzula zostanie znaleziona, znacznik jest umieszczany w nowym miejscu.
Unifikacja Reguły decydujące czy cel można zunifikować z głową klauzuli .W przypadku użycia klauzuli pierwotnie wszystkie zmienne są nieukonkretnione. Nieukonkretniona zmienna unifikuje się z dowolnym obiektem. W wyniku tego zmienna będzie zastąpiona przez ten obiekt. Jeśli zmienna nie jest nieukonkretniona, liczba całkowita lub atom unifikują się jedynie z samymi sobą. Jeśli nie zachodzi żaden z powyższych przypadków, struktura unifikuje się z inną strukturą o takim samym funktorze i takiej samej liczbie argumentów, zaś odpowiadające sobie argumenty też muszą się unifikować.
Unifikacja Warto wspomnieć o unifikacji dwóch nieukonkretnionych zmiennych. W efekcie zmienne stają się ze sobą powiązane czyli będą miały taką samą wartość w momencie ukonkretnienia którejkolwiek z nich. Skojarzenie unifikacji z porównywaniem nie jest przypadkiem ponieważ predykat = stara się, aby jego argumenty były równe, unifikując je ze sobą.
Unifikacja Zbierając wszystko to o czym mowa była wcześniej czyli operatorach, arytmetyce i unifikacji załóżmy, że w bazie danych mamy następujące zapisy: suma(5). suma(3). suma(X+Y). Niech dane będzie zapytanie: ?- suma(2+3). Który z faktów podanych wyżej da się zunifikować z takim zapytaniem? W zapytaniu argumentem struktury suma jest komponent mający jako funktor znak plus i jako argumenty 2 i 3. Pokazany cel unifikuje się z faktem trzecim, zmienna X zostanie ukonkretniona wartością 2, zaś zmienna Y — wartością 3. Gdybyśmy chcieli wyliczyć sumę, musielibyśmy użyć operatora is: ?- X is 2+3.
Unifikacja W ramach ćwiczeń stwórzmy predykat add (dodaj) wiążący dwie liczby całkowite z ich sumą: dodaj(X, Y, Z) :- Z is X+Y. Z samej definicji, X i Y muszą być ukonkretnione.
Dziękujemy za uwagę