Programowanie w logice Prolog 3
Predykaty wbudowane Predykaty wbudowane to predykaty, których definicje są z góry znane systemowi a zatem nie ma konieczności ich definiowania. Predykaty wbudowane mogą realizować zadania, których nie da się zaprogramować w czystym Prologu. mogą też ułatwiać pracę programiście.
Predykaty wbudowane var(x) Predykat var(x) jest spełniony jeżeli X jest zmienną nieukonkretnioną. Przykład:?- var(x). true.?- X=3,var(X). false.?- var(x). true.?- var(x),x=4. X = 4.
Predykaty wbudowane nonvar(x) Predykat nonvar(x) jest spełniony jeżeli X jest zmienną ukonkretnioną. Przykład:?- nonvar(x). false.?- X=3,nonvar(X). X = 3.?- nonvar(4). true.?- nonvar(abc). true.?- nonvar(abc),fail. false.
Predykaty wbudowane atom(x) Predykat atom(x) jest spełniony jeżeli X jest atomem. Przykład:?- atom(x). false.?- atom(23). false.?- atom(mama). true.?- atom('mama i tata'). true.?- atom("mama i tata"). false.?- X=24,atom(X). false.
Predykaty wbudowane number(x) Predykat number(x) jest spełniony jeżeli X jest liczbą. Przykład:?- number(x). false.?- X=1,number(X). X = 1.?- number(3). true.?- number(a). false.?- number('3'). false.?- atom('3'). true.
Predykaty wbudowane atomic(x) Cel atomic(x) nie zawodzi jeżeli X jest liczbą lub atomem. Przykład:?- atomic('3'). true.?- atomic(3). true.?- atomic('a b c'). true.?- atomic(x). false.?- X=3,atomic(X). X = 3.
Predykaty wbudowane atomic(x) Zauważmy, że predykat atomic(x) można zdefiniować wykorzystują atom i number: podobnie: atomic(x):-atom(x). atomic(x):-number(x). nonvar(x):-var(x),!,fail. nonvar(_).
Predykaty wbudowane listing(a) Predykat listing(a) służy do wypisania wszystkich klauzul predykatu o nazwie A. Przykład: lubi(tomek,ryby). lubi(tomek,ala). lubi(ala,x):-lubi(x,ksiazka).?- listing(lubi). lubi(tomek,ryby). lubi(tomek,ala). lubi(ala,a):-lubi(a,ksiazka). true.
Predykaty wbudowane asserta(x),assertz(x) Predykat asserta(x) służy do dodania klauzul na początku bazy danych. Zmienna X musi być ukonkretniona. Predykat assertz(x) służy do dodania klauzul na końcu bazy danych. Zmienna X musi być ukonkretniona. Przykład:?- ojciec(x,y). ERROR: toplevel: Undefined procedure: ojciec/2 (DWIM could not correct goal)
Predykaty wbudowane asserta(x),assertz(x) Przykład:?- asserta(ojciec(marek,pawel)). true.?- listing(ojciec). :- dynamic ojciec/2. ojciec(marek, pawel). true.?- asserta(ojciec(marek,kasia)). true.?- listing(ojciec). :- dynamic ojciec/2. ojciec(marek, kasia). ojciec(marek, pawel). true.
Predykaty wbudowane asserta(x),assertz(x) Przykład:?- assertz(ojciec(marek,julia)). true.?- listing(ojciec). :- dynamic ojciec/2. ojciec(marek, kasia). ojciec(marek, pawel). ojciec(marek, julia). true.
Predykaty wbudowane retract(x) Predykat retract(x) służy do usunięcia klauzul z bazy danych odpowiadających termowi X. Przykład:?- ojciec(x,y). X = pawel, Y = marek ; X = pawel, Y = kasia.?- retract(ojciec(pawel,kasia)). true.?- ojciec(x,y). X = pawel, Y = marek.
Predykaty wbudowane retract(x) Przykład:?- ojciec(x,y). X = pawel, Y = kasia ; X = pawel, Y = marek.?- retract(ojciec(x,y)). X = pawel, Y = kasia ; X = pawel, Y = marek.?- ojciec(x,y). false.
Czytanie i pisanie termów Do czytania termu służy predykat read. Jeżeli zmienna X jest nieukonkretniona wówczas cel read(x). odczyta następny term i ukonkretni nim zmienną X. Przykład:?- read(x). : marek. X = marek.?- read(x). : pawel. X = pawel.
Czytanie i pisanie termów Przykład: zdarzenie(1410,'bitwa pd Grunwaldem'). zdarzenie(1772,'pierwszy rozbiór Polski'). zdarzenie(1939,'wybuch II wojny swiatowej'). pytanie(y):-read(x),zdarzenie(x,y). Wówczas:?- pytanie(x). : 1939. X = 'Wybuch II wojny swiatowej'.
Czytanie i pisanie termów Do pisania termu służy predykat write. Jeżeli zmienna X jest ukonkretniona termem wówczas cel write(x). spowoduje wypisanie termu na ekranie. W przeciwnym razie (zmienna X nie jest ukonkretniona termem) wyświetlona zostanie zmienna z niepowtarzalnym numerem. Przykład:?- write(x). _G235 true.
Czytanie i pisanie termów Przykład: zdarzenie(1410,'bitwa pd Grunwaldem'). zdarzenie(1772,'pierwszy rozbiór Polski'). zdarzenie(1939,'wybuch II wojny swiatowej'). pytanie:- write('podaj rok:'), read(x), zdarzenie(x,y), write(y). Wówczas:?- pytanie. Podaj rok: 1772. Pierwszy rozbiór Polski true.
Wypisanie listy Klauzula wypiszliste(l) wypisuje listę L na ekranie w taki sposób, że każdy term pojawia się w innym wierszu: wypiszliste([]):-!. wypiszliste([x Y]):-write(X), nl,wypiszliste(y). Przykład:?-wypiszListe([1,3,'Sobota']). 1 3 Sobota true.
Czytanie i pisanie termów Przykład zdarzenie(1410,['bitwa pd Grunwaldem','Zmarl antypapiez Aleksander V']). zdarzenie(1772,['pierwszy rozbiór Polski','Bitwa morska pod Patras']). zdarzenie(1939,['wybuch II wojny swiatowej','powstala firma Hewlett- Packard','Podpisano pakt stalowy']). wypiszliste([]):-!. wypiszliste([x Y]):-write(X), nl,wypiszliste(y),!.
Czytanie i pisanie termów Przykład (cd) rok(x):- zdarzenie(x,y), wypiszliste(y). pytanie:- write('podaj rok: '), read(d), rok(d).
Czytanie i pisanie termów Przykład:?- pytanie. Podaj rok: 1772. Pierwszy rozbiór Polski Bitwa morska pod Patras true.?- pytanie. Podaj rok: 1815. false.?- pytanie. Podaj rok: 1939 Wybuch II wojny swiatowej Powstala firma Hewlett-Packard Podpisano pakt stalowy true.
Operacje na plikach W języku Prolog operacje na plikach opierają się na koncepcji strumienia. Strumieniem może być dowolny plik o zapisie sekwencyjnym (tekstowy). Terminal użytkownika też jest strumieniem. Dane są czytane ze strumienia wejściowego (domyślnie terminal użytkownika) i zapisywane w strumieniu wyjściowym (domyślnie terminal użytkownika).
Operacje na plikach W danej chwili realizowana może być operacja odczytu i zapisu odpowiednio z/do jednego strumienia wejściowego i jednego strumienia wyjściowego. strumień wejściowy terminal użytkownika strumień wyjściowy plik A program plik B
Czytanie i pisanie z/do plików W dotychczasowych przykładach wykorzystywany był domyślny strumień wejścia/wyjścia tzw. user_input oraz user_output. Prolog pozwala nam też czytać z plików i zapisywać do plików. Praca z plikami możliwa jest dzięki predykatom: open powiązanie strumienia z plikiem. close odłącznie strumienia od pliku.
Czytanie i pisanie z/do plików Argumenty predykatu open: nazwa pliku. tryb otwarcia - możliwe wartości: read otwarcie do odczytu istniejącego pliku; write utworzenie nowego pliku do zapisu (jeśli plik istnieje, zostanie usunięty); readwrite tryb zapisu i odczytu (jeśli plik istnieje to zostanie otworzony plik istniejący w przeciwnym razie plik zostanie utworzony); append istniejący plik zostanie otworzony do dopisywania.
Czytanie z plików Przykładowa struktura programu pracującego w plikiem: czytajplik :- open('dane.txt',read,x), kododczytujacy, close(x). X to zmienna, która zostanie związana ze strumieniem Aby w predykacie kododczytujacy móc odczytać (zapisać) dane z (do) pliku musimy wcześniej zmienić strumień wejściowy (wyjściowy). Zmiana bieżącego strumienia wejściowego i wyjściowego odbywa się za pomocą predykatów set_input oraz set_output.
Czytanie z plików Zmodyfikujmy nasz program: czytajplik :- open('dane.txt',read,x), current_input(ci), set_input(x), kododczytujacy, close(x), set_input(ci). CI to zmienna której wartością jest strumień związany z klawiaturą (linia numer 3). Jej wartość ustalona jest za pomocą predykatu current_input.
Czytanie z plików Brakujący predykat: kododczytujacy:- read(term), obsluz(term). obsluz(end_of_file):-!. obsluz(term):- write(term),nl, kododczytujacy. Predykat obsluz kończy działanie programu po napotkaniu końca pliku. W przeciwnym razie wypisuje term i wywołuje predykat kododczytujacy.
Czytanie z plików Ostatecznie nasz program ma postać: czytajplik :- open('dane.txt',read,x), current_input(ci), set_input(x), kododczytujacy, close(x), set_input(ci). kododczytujacy :- read(term), obsluz(term). obsluz(end_of_file):-!. obsluz(term) :- write(term),nl,kododczytujacy.
Czytanie z plików Przetestujmy nasz program na pliku: Wówczas: 1. abc. 2. def. 3. ghi. 4. jkl.?- czytajplik. 1 abc 2 def 3 ghi 4 jkl true.
Czytanie z plików Kropka musi się pojawić po każdym wyrazie: Wówczas: 1. abc. 2. def. 3. ghi 4. jkl.?- czytajplik. 1 abc 2 def 3 ERROR: dane.txt:3: Syntax error: Operator expected Brak kropki!
Czytanie z plików Jeszcze jedna modyfikacja: Wówczas:?- czytajplik. 1 abc 2 def 3 ghi 4 jkl true. 1. abc. 2. def. '3 ghi'. 4. jkl. Apostrofy!
Czytanie z plików No i ostatnia modyfikacja: Wówczas:?- czytajplik. 1 abc 2 def [51,32,103,104,105] 4 jkl true. 1. abc. 2. def. "3 ghi". 4. jkl. Cudzysłów!
Pisanie do pliku Program zapisujący do pliku: zapiszplik:- open('out.txt',write,x), current_output(co), set_output(x), kodzapisujacy, close(x), set_output(co). CO to zmienna której wartością jest strumień związany z ekranem (linia numer 3). Jej wartość ustalona jest za pomocą predykatu current_output.
Pisanie do pliku Brakujący predykat: kodzapisujacy:- read(x),\+(x='k'), write(x),nl, flush_output, kodzapisujacy. Predykat flush_output czyści strumień wyjściowy, w szczególności umożliwia pisanie od początku nowej linii. Wpisanie k. powoduje zakończenie pracy programu.
Pisanie do pliku Ostatecznie nasz program ma postać: zapiszplik:- open('out.txt',write,x), current_output(co), set_output(x), kodzapisujacy, close(x), set_output(co). kodzapisujacy:- read(x),\+(x='k'), write(x),nl, flush_output, kodzapisujacy.
Pisanie do pliku Przetestujmy nasz program:?- zapiszplik. : abc. : def. : ghj. : k. Zawartość pliku out.txt: abc def ghj
Pisanie do pliku Jeszcze jeden test: zapiszplik. : Pierwsza linijka. ERROR: Stream user_input:65:12 Syntax error: Operator expected UWAGA: Po każdym termie musi się pojawić kropka.
Pisanie do pliku No i ostatni test naszego programu:?- zapiszplik. : 'Pierwsza linijka'. : 'Druga linijka'. : 'Ostatnia linijka'. : k. false. Apostrofy! Zawartość pliku out.txt: Pierwsza linijka Druga linijka Ostatnia linijka
Pisanie do pliku Rozważmy teraz następujący program: zapiszdopliku(dane,gdzie) :- open(gdzie,append,x), current_output(co), set_output(x), kodzapisujacy(dane), close(x), set_output(co). kodzapisujacy(dane) :- write(dane),nl.
Czytanie z plików Test programu:?- zapiszdopliku('dane do pliku','jakisplik.txt'). true.?- zapiszdopliku('dane do pliku 2','jakisplik.txt'). true. Zawartość pliku out.txt: dane do pliku dane do pliku 2
Kryptarytmy Kryptarytm - zadanie szaradziarskie, w którym litery należy zastąpić cyframi tak, aby liczby, które w ten sposób powstaną, tworzyły poprawne działania. Każdej literze odpowiada jedna cyfra, różnym literom różne cyfry. Kryptarytmy można rozwiązać za pomocą odpowiedniego rozumowania bez rozważania wielu przykładów. Kryptarytm może posiadać więcej niż jedno rozwiązanie.
Kryptarytmy Przykłady:
Kryptarytmy Przykłady:
Kryptarytmy Katarzyna Lipszyc Kryptarytmy czyli arytmetyka słów
Kryptarytmy Chcemy w Prologu rozwiązać następujący kryptarytm: Przypomnijmy sobie jak działa system Prologu.
Powtórzenie Rozważmy zapytanie:?- lubi(tomek,ryby). Jeżeli zadajemy zapytanie Prolog przeszukuje bazę danych i szuka faktów pasujących do faktu podanego w zapytaniu. Dwa fakty pasują do siebie jeżeli mają te same predykaty (tak samo pisane) i te same argumenty. Jeżeli poszukiwanie zakończy się sukcesem Prolog odpowiada YES (TRUE), w przeciwnym razie NO (FALSE).
Powtórzenie Zapytanie może się składać z kilku celów np.:?- lubi(tomek,sport),lubi(ania,ksiazki). Prolog przeszukuje bazę danych i stara się osiągnąć cele w kolejności od lewej do prawej. Jeśli któryś z celów nie może zostać osiągnięty, wówczas następuje niepowodzenie. Prolog nawraca do poprzednio osiągniętego celu i próbuje osiągnąć go w inny sposób, który być może pozwoli osiągnąć także następne cele.
Kryptarytmy Wracamy do naszego problemu: Litery S,E,N,D,M,O,R,Y onaczają wybrane cyfry ze zbioru 0,1,2,3,4,5,6,7,8,9. Zatem lista [S,E,N,D,M,O,R,Y,A,B] musi być permutacją listy [0,1,2,3,4,5,6,7,8,9]. Zatem musi być osiągnięty następujący cel: permut([s,e,n,d,m,o,r,y,a,b],[0,1,2,3,4,5,6, 7,8,9]).
Permutacja listy Chcemy zdefiniować predykat: permut(l1,l2). Powyższa klauzula jest prawdziwa, jeśli lista L2 jest permutacją listy L1. Definicja : Jeżeli pierwsza lista (L1) jest pusta, to druga lista (L2) również jest pusta. Najpierw usuwamy element X, na pozostałej reszcie L1 dokonujemy permutacji i wstawiamy element X na początek poddanej już permutacji reszcie listy (czyli P).
Permutacja listy Formalna definicja: permut([],[]). permut(l,[x P]):-usun(X,L,L1),permut(L1,P). Przykład:?- permut([a,b,c],[a,c,b]). true.?- permut([a,b,c],[a,c,d]). false.?- permut([a,b,c],x). X = [a, b, c] ; X = [a, c, b] ; X = [b, a, c] ; X = [b, c, a] ; X = [c, a, b] ; X = [c, b, a] ; false.
Kryptarytmy Dowolną liczbę będziemy reprezentować za pomocą listy zawierającej kolejne cyfry liczby: 0 [] 3456 [3,4,5,6] 6853299 [6,8,5,3,2,9,9] Musimy mieć predykat pozwalający konwertować listę reprezentującą liczbę na wartość tej liczby.
Kryptarytmy Jak taką wartość wyliczyć? Inaczej: Formalna definicja: [3,4,5,6] = 3*1000+4*100+5*10+6 [3,4,5,6] = ((10*3+4)*10+5)*10+6 wartosc([],0). wartosc([n],n). wartosc([h1,h2 T],N):-H3 is 10*H1+H2, wartosc([h3 T],N).
Kryptarytmy Przetestujmy:?- wartosc([1,2,3],121). false.?- wartosc([1,2,3],123). true.?- wartosc([],x). X = 0.?- wartosc([1,2,3,4,5],x). X = 12345.?- wartosc([1,2,3,4,5,2,3,4],x). X = 12345234.
Kryptarytmy Potrzebujemy jeszcze predykat suma/3, który pozwoli dodać kilka liczb (reprezentowanych listami i umieszczonych na liście będącej pierwszym argumentem) do liczby będącej drugim argumentem tzn.:?- suma([[1,2,3]],5,x). X = 128.?- suma([[1,2,3],[4,5,1]],5,x). X = 579.?- suma([[1,2,3],[4,5,1],[5,6,9,6]],4,x). X = 6274.
Kryptarytmy Formalna definicja: suma([],x,x).? Propozycja rozwiązania: Pobieramy pierwszą liczbę z listy (czyli głowę listy) Obliczamy wartość tej liczby Dodajemy tę wartość do drugiej liczby i zapisujemy w drugim argumencie.
Kryptarytmy Otrzymujemy zatem następujące cele: perm([s,e,n,d,m,o,r,y,a,b],[0,1,2,3,4,5,6,7,8,9]), suma([[s,e,n,d], [M,O,R,E]],Z), wartosc([m,o,n,e,y],z)
Kryptarytmy Nasz docelowy predykat możemy zdefiniować następująco: kryptarytm([s,e,n,d,m,o,r,y,a,b]):- perm([s,e,n,d,m,o,r,y,a,b],[0,1,2,3,4,5,6,7,8,9]), suma([[s,e,n,d], [M,O,R,E]],Z), wartosc([m,o,n,e,y],z). kryptarytm([s,e,n,d,m,o,r,y]):- kryptarytm([s,e,n,d,m,o,r,y,_,_]).
Kryptarytmy Sprawdzamy:?- kryptarytm([s,e,n,d,m,o,r,y]). S = 6, E = 4, N = 1, D = 9, M = 0, O = 7, R = 2, Y = 3. SEND 6419 +MORE +0724 MONEY 07143
Grafy Rozważmy następujący graf: 1 2 5 3 4 Chcemy napisać program, który dla dwóch zadanych wierzchołków wypisze nam możliwe ścieżki między nimi.
Grafy Graf opisujemy następująco: krawedz(1,2). krawedz(2,3). krawedz(1,5). krawedz(4,5). krawedz(5,2). krawedz(2,4). krawedz(3,1). 5 1 4 2 3 Wierzchołki są połączone jeżeli istnieje między nimi krawędź: polacz(x,y):-krawedz(x,y);krawedz(y,x). alternatywa
Akumulatory Często zdarza się, że w celu uzyskania wyniku konieczne jest przeglądanie struktur prologowych. Podczas analizy takich struktur mogą pojawić się wyniki pośrednie. Wyniki te możemy zapisać w dodatkowym argumencie predykatu, który nazywamy akumulatorem.
Grafy Wykorzystamy następujące predykaty: odwroc odwrócenie listy akumulator odwroc([x Y],Z,W):-odwroc(Y,[X Z],W). odwroc([],x,x). odwroc(a,r):-odwroc(a,[],r). Przykład:?- odwroc([2,5,7],[],a). A = [7,5,2].?- odwroc([2,5,7],a). A = [7,5,2]. odwroc([2,5,7],[],a). odwroc([5,7],[2],a). odwroc([7],[5,2],a). odwroc([],[7,5,2],a).
Grafy Wykorzystamy następujące predykaty: nalezy sprawdzenie czy element należy do listy nalezy(x,[x _]). nalezy(x,[_ R]):-nalezy(X,R). Przykład:?- nalezy(1,[1,4,5]). true ; false.?- nalezy(7,[1,4,5]). false.?- nalezy(x,[1,5]). X = 1 ; X = 5 ; false.
Grafy Wykorzystamy następujące predykaty: travel akumulator travel(a,b,p,[b P]):-polacz(A,B). travel(a,b,odwiedzone,path):- polacz(a,c), C \== B, not(nalezy(c,odwiedzone)), travel(c,b,[c Odwiedzone],Path). Przykład:?- travel(1,2,a,b). B = [2 A] ; false. krawedz(1,2). krawedz(2,3). krawedz(3,4).
Grafy - przykład Przykład: travel(a,b,p,[b P]):-polacz(A,B). travel(a,b,odwiedzone,path):- polacz(a,c), C \== B, not(nalezy(c,odwiedzone)), travel(c,b,[c Odwiedzone],Path). 1 2 3?- travel(1,4,[],a). A = [4, 3, 2]?- travel(1,4,[1],a). A = [4, 3, 2, 1] ; false. 4?- travel(2,4,[1,2],a). A = [4, 3, 1, 2] ; false.
Grafy - przykład Ostatnim wykorzystanym predykatem jest: sciezka sciezka(a,b,sciezka) :- travel(a,b,[a],q), odwroc(q,sciezka). Przykład:?- sciezka(1,3,a). A = [1, 2, 3] ; false.?- sciezka(1,5,a). false. 1 4 2 3
Grafy - przykład Przykład:?- sciezka(4,3,x). X = [4, 5, 2, 3] ; X = [4, 5, 2, 1, 3] ; X = [4, 5, 1, 3] ; X = [4, 5, 1, 2, 3] ; X = [4, 2, 3] ; X = [4, 2, 1, 3] ; X = [4, 2, 5, 1, 3] ; false. 5 1 4 2 3
Grafy - przykład Przykład:?- sciezka(4,2,x). X = [4, 5, 1, 2] ; X = [4, 3, 2] ; false. 5 1 2 3 4?- sciezka(4,2,x). X = [4, 5, 2] ; X = [4, 5, 1, 2] ; X = [4, 3, 2] ; false. 5 1 4 2 3
Koniec