Prolog - programowanie w języku logiki

PROLOG jest językiem nietypowym, programowanie w nim przypomina bardziej rozmowę niż operowanie nazwami zastrzeżonymi czy rozkazami jak w BA-SIC-u i PASCAL-u. Służy on do przetwarzania języków naturalnych, list danych itp...

 

PROLOG jest językiem nietypowym, programowanie w nim przypomina bardziej rozmowę niż operowanie nazwami zastrzeżonymi czy rozkazami jak w BA-SIC-u i PASCAL-u. Służy on do przetwarzania języków naturalnych, list danych itp... Szczególnie nadaje się do budowania inteligentnych baz danych o dostępie w języku naturalnym, Kompilatorów, systemów strategicznych, języków problemowych czy programów sprawdzających poprawność dowodów twierdzeń.

Pełną definicję języka PROLOG opracował w 1972 r. Alain Colmeraur. PROLOG dostępny jest na wielu mikrokomputerach opartych na mikroprocesorach: Z-80 — pod systemem CP/M-80 oraz 8088/86 podsystemem MSDOS i komputerach wyposażonych w system operacyjny UNIX.

Implementacją PROLOG-u na komputer ZX--Spectrum jest micro-PROLOG. Ponieważ jego syntaktyka mogłaby się wydawać nieco zawiła dla osób nie obeznanych z gramatykami metamorficznymi, opracowano pewne rozszerzenie języka podstawowego o nazwie SIMPLE. Tak więc w pierwszej kolejności nagrywany program PROLOG a następnie SIMPLE (komendą load SIMPLE). Na kasecie firmowej po głównym pliku zawierającym Prolog znajduje się kilkadziesiąt plików o kolejnych nazwach SIMPLE, SIMTRACE, są to programy systemowe, do użytku tylko przez Prolog.

Rozpoczniemy od podawania przykładów w składni uproszczonej. Przykłady zaczerpnięto z książki Clark K.L. Emmals R., McCabe F.G. „A micro-PROLOG Primer" Logic Programming Associates L.T.D., 1983.

Podstawowe wyobrażenia w PROLOG-u to twierdzenia i pytania. Twierdzenia określają pewien obiekt lub ich grupę oraz ustalają relacje między nimi. Oto przykład zdań poprawnych pod względem logicznym: Jan jest ojcem Piotra, Darek jest bratem Piotra. Nie są natomiast zdaniami w sensie logicznym następujące stwierdzenia: Czy jutro będzie pogoda? Chyba pójdę do kina.

Zdania: Jan jest ojcem Piotra i Darek jest bratem Piotra, moglibyśmy zapisać poprawnie pod względem syntaktycznym następująco:

Znak "&." ukazuje się zawsze na początku nowej linii i oznacza gotowość systemu do przyjęcia kolejnego zlecenia. Wysłanie przez system komunikatu "Error: 2" oznacza, że program SIMPLE nie został nagrany. Należy go nagrać komendą load SIMPLE i powtórzyć poprzednio wykonane operacje. &.add (John father-of Peter) &.add (Dark brother-of Peter) Relacje zachodzące między obiektami można zapisywać w formie postfiksowej, tj. takiej, w której nazwa własności występuje po nazwie obiektu, posiadającego tę własność. &.Henry male Henryk — płeć męska &.Jane female Jane — płeć żeńska O zdaniu, w którym nazwa relacji poprzedza listę obiektów, mówimy, że ma formę prefiksową.

&.gives (John Mary flower) — daje (Jan Marii kwiat)

&.reads (Mark book) — czyta (Marek książkę)

Nawias zastosowano w celu oddzielenia obiektów od relacji.

Zaś relację, w której jej nazwa występuje między obiektami nazywamy relacją infiksową np.

&.Henry father-of Elizabeth Henryk ojciec Elżbiety.

Podstawową formą relacji jest forma prefiksową. Zdania dwuskładnikowe mogą również być pisane w formie prefiksowej.

Stwierdzenia:

father-of (Henry Elizabeth)

oraz

Henry father-of Elizabeth

są równoważne.

W matematyce i logice obiekty, między którymi zachodzi relacja nazywamy argumentami. Mówimy

o pierwszym, drugim itd., argumencie. Warto pamiętać, że micro-PROLÓG wypisuje zdania zawsze w formie postfiksowej.

Wiedza, którą już posiadamy, pozwala nam na stworzenie małej bazy danych. Będzie ona opisywała relacje zachodzące w pewnej rodzinie. Przy okazji poznamy wszystkie komendy PROLOG-u. Nie jest ich wiele.

Wprowadźmy następujące zdania.

&.add (Elizabeth mother-of Henry)

&.add (Katherine mother-of Maryj

&.add (Ann mother-of Elizabeth 2)

&.add (Henry father-of Edward)

&.add (Jane mother-of Edward)

&.add (Henry-Snr male)

&.add (Elizabeth 2 female)

&.add (Katherine female)

&.add (Mary female) &.add (Elizabeth 2 female)

&.add (Ann female)

&.add (Female (Jane))

&.add (Male (Edward))

Ostatnie dwa zdania zapisaliśmy w formie prefiksowej. Przy pomocy zlecenia add możemy dodawać do naszego zbioru w każdej chwili dowolną ilość informacji w postaci zdań. Dane, które dotychczas wprowadziliśmy, są pogrupowane pod względem relacji, jakie między nimi zachodzą. PROLOG „zna więc następujące obiekty:

Henry-Snr

Henry

Mary

Elizabeth

Elizabeth 2

Ann

Edward

Jane oraz relacje:

father-of

mother-of

male

female

Istnieje komenda, która znacznie przyspiesza wprowadzenie listy obiektów o tej samej własności. Jest nią accept. Po wpisaniu accept male (lista mężczyzn) otrzymujemy: male i teraz wpisujemy nazwę obiektu (na zakończenie przyciskamy Klawisz ENTER). W nowej linii ukazuje się kolejne male i system oczekuje na wprowadzenie nowego obieku lub słowa end kończącego wprowadzenie listy obiektów. Np.:

accept małe

male. (Henry-Snr)

male. (Henry)

male. (Edward) czytamy teraz nasze dane używając komendy list all

&.list all

Henry-Snr father-of Henry Henry father-of Mary Henry father-of Elizabeth Henry father-of Edward Elizabeth mother-of Henry Katherine mother-of Mary Ann mother-of Elizabeth 2 Jane mother-of Edward Henry-Snr male Henry male itd.

Możemy wybrać pojedynczą relację i wypisać obiekty spełniające ją. Uczynimy to w następujący sposób: po komendzie list wypiszemy nazwę relacji

& list mother-of Elizabeth mother-of Henry Katherine mother-of Mary Ann mother-of Elizabeth 2 Jane mother-of Edward &

Aby zapisać ten plik danych na taśmie piszemy:

&.save RODZINA Z powrotem ładujemy do komputera plik rozkazem

&.load RODZINA

Kasowanie lub dopisywanie dowolnych zdań w micro-PROLOG-u jest bardzo proste. Zdanie: Katherine mother-of Mary możemy skasować w dwojaki sposób. Pisząc

&.delete (Katherine mother-of Mary) lub

&.delete mother-of 2

W pierwszym przypadku wskazujemy dokładnie na relację, w drugim czynimy to pośrednio przez wskazanie numeru, pod którym dana relacja się znajduje. Podobnie jeśli przy instrukcji add podamy numer, to zdanie, które wpiszemy znajdzie się w odpowiednim miejscu.

add.5 (Katherine mother-of Mary) Komenda kill w połączeniu z nazwą relacji kasuje wszystkie zdania wykorzystując daną relację Kill male

Cały program kasujemy przy pomocy Kill all. Istnieje także komenda NEW. Kasuje ona nie tylko wszystkie dane, lecz i program SIMPLE. Po użyciu tej komendy trzeba powtórnie załadować SIMPLE.

Potrafimy już tworzyć zbiory danych i czytać je. Obecnie nauczymy się zadawać komputerowi pytania tak, by uzyskać na nie odpowiedzi. Nadal będziemy się posługiwali danymi dotyczącymi rodziny. Najprostsza formą pytania jest prośba o potwierdzenie faktu. Pytamy się, czy Henryk jest ojcem Elżbiety 2? W PROLOG-u pytanie to zadajemy w sposób następujący:

&.is (Henry father-of Elizabeth 2) na co PROLOG odpowiada:

YES

Odpowiedź na pytanie: is (.....) polega, po prostu,

na sprawdzeniu czy zdanie (.....) lub inne, równo ważne, figuruje na liście danych. Dużo bardziejskomplikowane jest pytanie typu: Czy jest znana matka Marii?

W PROLOG-u pytanie takie wygląda następująco:

&.is (x mother-of Mary) Czyli: czy znany jest taki obiekt x, że zdanie: x mother-of Mary jest prawdziwe. PROLOG znajduje zdanie: Katherine mother-of Mary i wysyła odpowiedź YES

W tym przypadku x jest zmienną. Zmienna jest traktowana w PROLOG-u jako obiekt nieznany. Jej odpowiednikiem może byc w języku naturalnym na przykład „ktoś” „coś”. Zmienne oznaczamy literami x,y,z,X,Y,Z, (duże litery oznaczają zbiory). W przypadku większej ilości zmiennych, możemy je indeksować np. x1, x2, x3...

Kto jest ojcem Edwarda? W PROLOG-u piszemy:

&.which (x: x father-of Edward)

czyli: znajdź taki obiekt x, że prawdziwe jest zdanie: x father-of Edward. PROLOG dopuszcza także pytania złożone, np.: Czy Henryk senior jest ojcem Henryka i Edwarda?

&.is (Henry-Snr father-of Henry 1. and Henry-Snr father-of Edward) NO

Znak 1 pojawia się po przejściu do nowej linii (naciśnięcie klawisza ENTER) i oznacza, że zdanie nie zostało zamknięte znakiem) i może być kontynuowane.

Do podstawowych relacji arytmetycznych należą: SUM, TIMES, LESS, INT.

Mogą one przyjmować wartość 1 (prawda), 0 (fałsz).

Relacja SUM (x y z) jest prawdziwa jedynie wtedy, gdy z = x + y.

&.is (SUM (30 30 50))

YES

Pytanie o wynik dodawania formułujemy w następujący sposób:

&.which (x: SUM (20 30 x))

50

Wynik odejmowania np.(50-30) możemy otrzymać na trzy sposoby:

&.which (x: SUM (50 - 30x))

20

lub:

&.which(x: SUM (30*50) 20

czy też: &.which (x: (x 30 50)) 20

W relacji SUM może występować tylko jedna niewiadoma. Relacja INT może służyć do sprawdzenia czy dana liczba jest całkowita lub zmiennoprzecinkowa bez części ułamkowej, oraz do wyznaczania całkowitej części liczby FP (Floating Point — zmiennoprzecinkowym).

Pytania formułujemy w sposób następujący:

&.is (45 INT)

YES

&.is (4-67 INT) NO

&.is (3.567E3 INT) YES

Natomiast przy wyznaczaniu części całkowitej piszemy:

&.which (x:3.45 INT x)

3

&.which (x:3.56398E3 INT x) 3563

Żeby sprawdzić czy jakaś liczba jest częścią całkowitą innej, możemy połączyć relację INT z EQ (od ang. EQual — równe).

Relacja TIMES ma następującą definicję: TIMES (x y z) zachodzi wtedy i tylko wtedy, gdy z = x y. Relację TIMES użyć możemy (analogicznie jak SUM) na kilka sposobów:

&.is (TIMES (3 4 12))

YES

&.which (x: TIMES ( 3 4 x)) 12

&.which (x: TIMES (3 x 12)) &.is (TIMES (3 y 12) & y INT) YES

to ostatnie pytanie ma na celu sprawdzenie czy wynik dzielenia 12 przez 3 jest całkowity. Jeśli natomiast chcemy zrealizować dzielenie całkowite, piszemy:

&.which (x: TIMES (24 y 126) & x INT y) 5

ostatnie pytanie moglibyśmy zinterpretować następująco: „jaki x jest częścią całkowitą takiego y, że 24 X y = 126. Relacja LESS może być używana jedynie do sprawdzania pewnych wyrażeń:

LESS (x y) zachodzi wtedy i tylko wtedy, gdy x jest mniejsze od y.

&.is (3 LESS 4) daje odpowiedź

YES gdyż 3 jest mniejsze od 4. Podobnie na:

&.is (4 LESS 3)

Prolog odpowiada: NO

Również pytania: &.is (TIMES (3 x 10) & TIMES (3 x y) 1. SUM (y z 10) z LESS 0.1 E-5 YES

Cyfry ukazujące się z lewej strony ekranu oznaczają liczbę niezamkniętych nawiasów. Prolog nie pozostawia bez odpowiedzi. Bardziej zaawansowanym miłośnikom micro-Prolog-u pozostawiam analizę semantyczną powyższego pytania.

LESS może również porównywać zmienne łańcuchowe, szeregując je alfabetycznie.

&.is (FRED LESS FREDDY)

YES

&.is (ALBERT LESS HAROLD) YES

&.is (SAM LESS BILL) NO

Przy formułowaniu pytań należy pamiętać o tym, że Prolog wszystkim wyrażeniom logicznym i arytmetycznym nadaje wartości kolejno od strony lewej do prawej. Dlatego na pytanie:

&. which (x: SUM (y 10 x) TIMES (2 5 y)) Prolog odpowiada: (zbyt wiele zmiennych)

Too many variables, zaś na analogiczne:

&.which (x: TIMES (2 5 y) SUM (y 10 x))

20

 

„Wyśledzić moment historyczny, w którym liczydło dosięgło Rozumu, jest równie trudno, jak ów, co małpę przemienił w człowieka”. Stanisław Lem „GOLEM XIV”

 

Interesujący jest sposób, w jaki Prolog odpowiada na zwykłe pytania: „is (.....) gdzie ,......” jest dowolnym zdaniem nie zawierającym zmiennych np. by znaleźć odpowiedź na pytanie: &.is (Henry male)

Prolog wyszukuje wszystkie obiekty posiadające cechę male:

Henry-Snr male

Henry male

Edward male następnie przyrównuje Henry do pierwszego obiektu i jeśli są one równe, przechodzi do następnego.

Gdy znajduje obiekt Henry, to przekazuje wiadomość YES, w przeciwnym wypadku NO.

Gdy w takim pytaniu występuje zmienna, to Prolog najpierw stara się nadać jej jakąś wartość (liczbową lub literową), a cała dalsza procedura jest taka sama. Dlatego przy rozbudowanych pytaniach jest do sprawdzenia bardzo wiele warunków i czas oczekiwania na odpowiedź się wydłuża.

W celu głębszego zrozumienia oraz prześledzenia etapów wartościowania każdego zdania (pytania lub stwierdzenia) można skorzystać z programu SIMTRACE. Wczytujemy go komendą Load SIMTRACE

Blok SIMTRACE jest napisany w oryginalnym micro-Prologu (podobnie jak SIMPLE) i służy do śledzenia pracy systemu. Napiszmy:

&.all-trace x: Henry-Snr father-of x

1. and x male

Pierwszym wyrażeniem, którego wartość logiczną można zbadać, jest: Henry-Snr father-of x, dlatego SIMTRACE wypisuje wiadomość:

(1) Henry-Snr father-of x trace? z zapytaniem, czy śledzić przebieg dobierania obiektów do x w celu uzyskania logicznej prawdy.

Jeżeli chcemy oglądać przebieg procesu wartościowania pytania, naciskamy „y” lub ENTER, zaś „n” w przeciwnym przypadku. Jeśli naciśniemy „y” następna wiadomość wygląda następująco:

(1) solved: Henry-Snr father-of Mary Prolog odnalazł obiekty Mary o własności:

Henry-Snr father-of Mary Teraz SIMTRACE analizuje następny warunek i pisze:

(2) Maty male trace?

Po naciśnięciu „y” otrzymujemy failing (2) i zaraz potem failing (1)

Przyjrzyjmy się dokładnie działaniu SIMTRACE:

System rozpatrywał najpierw pytanie Henry-Snr father-of x. Pierwszym obiektem, znalezionym i spełniającym pierwszy warunek był X-Mary. Lecz następny warunek brzmiał: male. Prolog podstawił pod X Mary i uzyskał zdanie Mary male, nie znalazł go jednak w słowniku relacji, więc przyjął je za fałszywe. Blok SIMTRACE wysłał w tym momencie wiadomość o niespełnieniu drugiego warunku przez obiekt X-Mary stąd właśnie failing (2). Pozostało więc już tylko obliczenie koniunkcji dwóch zdań: prawdziwego i fałszywego, w wyniku którego SIMTRACE wysłał nową wiadomość: failing (1) oznaczającą niespełnienie koniunkcji obydwu warunków. Blok SIMTRACE możemy skasować komendą:

&.kill simtrace-mod

Znajomość pracy systemu przydaje się przy tworzeniu ekonomicznych pytań. Zdania:

&.which x: Henry father-of x and x male oraz

&.which x: male and Henry father-of x

dadzą tę samą odpowiedź z tą różnicą, że w pierwszym przypadku Prolog znajdzie wszystkie takie x, że Henry father-of x, a następnie sprawdzi, które spełniają warunek: x male, w drugim przypadku Prolog postąpi wręcz odwrotnie — najpierw znajdzie takie x, dla których wychodzi x male, a następnie sprawdzi, które z nich spełniają warunek: — Henry father-of x. W dużych bazach danych wielokrotnie większych niż nasza RODZINA odpowiedź na pierwsze pytanie zostanie udzielona bardzo szybko w porównaniu z drugim.

 

Adam Krauze