Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Term to: stała, zmienna, struktura. Każdy term zapisywany jest jako ciąg znaków, tworzących cztery kategorie: duże litery: A-Z małe litery: a-z cyfry:

Podobne prezentacje


Prezentacja na temat: "Term to: stała, zmienna, struktura. Każdy term zapisywany jest jako ciąg znaków, tworzących cztery kategorie: duże litery: A-Z małe litery: a-z cyfry:"— Zapis prezentacji:

1

2 Term to: stała, zmienna, struktura. Każdy term zapisywany jest jako ciąg znaków, tworzących cztery kategorie: duże litery: A-Z małe litery: a-z cyfry: 0-9 znaki specjalne

3 Stałą nazywamy konkretne obiekty lub relacje. Istnieją dwa rodzaje stałych: atomy liczby Przykład : jas, malgosia, posiada, je Atomy składają się z: symboli, liter, cyfr znaku podkreślenia (zaczynamy zawsze małą literą), dowolnych znaków, jeśli ujęte są w pojedynczy cudzysłów. Liczby: -17, 23, 99.9, 123e-3

4 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. Jak sprawdzić, czy ktoś lubi Jasia? W takich sytuacjach możemy użyć zmiennej anonimowej zapisywanej jako jeden znak podkreślenia. lubi(_,jas).

5 Struktura, inaczej term złożony, to obiekt złożony z innych obiektów. Przykład: posiada(Ewelina,prawo jazdy).

6 Zwykle łatwiej jest zrozumieć budowę struktury, gdy jest ona zapisana w postaci drzewa. W drzewie tym korzeniem jest funktor, a gałęziami elementy struktury. Ponadto struktury można zagnieżdżać.

7

8 Drzewa również mogą opisywać zmienne w strukturach, w szczególności ukazując powiązania między nimi. Przykład:

9 Lista to bardzo popularna struktura danych. Definiuje się ją jako ciąg uporządkowanych(tzn. kolejność ma znaczenie) elementów dowolnej długości. Elementy mogą być dowolnymi termami: stałymi zmiennymi innymi strukturami

10 Lista w Prologu to szczególny przypadek struktury, którą można zapisać w formie specjalnego rodzaju drzewa. Listę pustą oznaczamy poprzez [ ], a operatorem składania list jest. Ogólnie lista w Prologu dzieli się na dwie części : pierwszy element zwany głową oraz resztę zwaną ogonem

11 [a, b, c] w zapisie formalnym.(a,.(b,.(c, []))) [[1,2],[3]] w zapisie formalnym.(.(1,.(2, [])),.(.(3, []), []))

12 Wróćmy do kwestii głowy i ogona. W zapisie formalnym wygląda to następująco:.( głowa, ogon). Zapis ten ułatwia operator |, więc wygląda to tak: [ głowa|ogon] W takim razie przykłady z poprzedniego slajdu można zapisać następująco: [a|b|c] [[1|2]|[3]]

13 Zapis ten uwidacznia się nie tyle dla konkretnych list, co dla dopasowań. Rozważmy przykładową klauzulę: polaczListy( G, O, [ G| O]). Klauzula ta umożliwia połączenie list G i O (polaczListy(1,[2,3],X) da wynik X=[1,2,3]) rozdzielenie gotowej listy na dwie pomniejsze (polaczListy(X,Y,[1,2,3]) da wynik X=1,Y=[2,3])

14 Często konieczne jest przeszukiwanie struktur w Prologu celem znalezienia pewnych informacji. Kiedy struktury mogą mieć inne struktury jako argumenty, konieczne jest przeszukiwanie rekurencyjne

15 Aby zrozumieć to zagadnienie, posłużymy się przykładem. Napiszmy funkcję, która sprawdzi przynależność elementu do listy. Najpierw sprawdźmy, czy poszukiwany element jest w głowie naszej listy.

16 Zatem taka klauzula wygląda następująco nalezy( X, [X|_]). Jednak co w przypadku, gdy nasz element nie znajduje się w głowie?

17 Trzeba sprawdzić, czy poszukiwany element jest w ogonie. Najlepiej będzie sprawdzić, czy element jest w pierwszym elemencie ogona.

18 Klauzula sprawdzająca ten przypadek wygląda następująco: nalezy( X, [ _|O]) :- nalezy( X, O). Zauważmy, że klauzula ta odwołuje się do samej siebie.

19 W takim razie cała nasza funkcja wygląda następująco: nalezy( X, [ X| _]). nalezy( X, [ _|O]) :- nalezy(X, O).

20 Oczywiście naszą funkcję można wykorzystać dwojako: zgodnie z przeznaczeniem, czyli do sprawdzania, czy element należy do listy (nalezy(2,[1,2,3]). uzyskamy true.) wywołując nalezy(X,[1,2,3]). uzyskamy wszystkie elementy z listy [1,2,3] (czyli: X=1; X=2; X=3)

21 Istotną kwestią związaną z rekurencją jest to, czy jest ona lewostronna. Z taką sytuacją spotkamy się, jeśli reguła powoduje wywołanie takiego samego celu, jak cel, który ją wywołał. Zobaczmy to na przykładzie

22 Zdefiniujmy taką zależność: osoba(X) :- osoba(Y), matka(X, Y). osoba( adam). I zadajmy zapytanie osoba(X). Jak łatwo zauważyć, uzyskamy pętlę w teorii nieskończoną(w praktyce skończy się nam pamięć)

23 Jak to naprawić? Najłatwiej będzie po prostu zamienić kolejnością klauzule, tak aby rekurencja miała na czym się zawiesić. W większości programów fakty, takie jak osoba(adam), powinny być umieszczane przed regułami.

24 Jakie są predykaty, w których fakty powinny być na końcu? Jednym z takich predykatów jest sprawdzenie, czy podany element jest listą.

25 Definicja tego predykatu wygląda następująco: jestLista([ X| Y]) :- jestLista( Y). jestLista( [] ). Polega on na sprawdzeniu, czy ostatni element ogona jest listą pustą.

26 Niestety ten predykat nie jest odporny na zapętlenie, tzn. jeśli wywołamy jestLista(X)., to wpadniemy w pętlę. Istnieją owszem ulepszenia tego predykatu, żeby się nie zapętlał, jednak odbywa się to kosztem osłabienia działania

27 mocnejestLista([]). mocnejestLista([_|_]).

28 Wyobraźmy sobie rekurencję jako pewnego rodzaju drzewo, tzn. każde kolejne wywołanie jej powoduje utworzenie nowego poziomu w drzewie. Jeżeli w którymś momencie osiągamy coś niepożądanego, to cofamy się w rekurencji do poziomu wyżej anulując dotychczasowe wyniki i wybieramy kolejną opcję.

29 Podobnie działa interpreter Prologa. Podczas działania tworzy on drzewo w głąb. Jeżeli coś zawodzi, anuluje ostatni krok i wyniki z nim związane oraz wybiera następną pasującą klauzurę. Działanie to nazywamy nawrotem. Oczywiście może okazać się, że piętro wyżej nie ma już wolnych klauzur, więc cofamy się o kolejne piętro do góry…

30 … i w górę i w górę … aż znajdziemy się w korzeniu i nie będzie alternatywnych klauzur do rozważenia. Wówczas osiągniemy wartość false oznaczającą zawód globalny.

31 Jednakże dzięki nawrotowi możemy uzyskać wszystkie możliwe rozwiązania danego zapytania, np. nalezy(X,[1,2,3]). dzięki mechanizmowi nawrotów wyświetli wszystkie elementy listy [1,2,3].

32 Pewną kontrolę nad nawrotami daje nam bezargumentowy funktor odcięcia wyrażany za pomocą !. Dojście do niego powoduje, że od chwili wykorzystania w rekurencji klauzuli zawierającej owo odcięcie do chwili dojścia do niego jako podcelu zostają uznane za ostateczne, czyli nie mogą być anulowane.

33 Najlepiej będzie to widać na przykładzie: Załóżmy, że nasza klauzula wygląda następująco: a(X) :- b(X), c(X), !, d(X). Dojście do odcięcia uniemożliwia nawrót do b(X) i c(X), zatem jeśli zawiedzie d(X), to zawiedzie całe a(X).

34 Można je podzielić na 3 grupy 1) Kiedy chcemy poinformować, że znaleźliśmy odpowiednią regułę. 2) Kiedy chcemy poinformować, że dany cel ma zawieść bez sprawdzenia alternatywnych rozwiązań 3) Kiedy należy zaprzestać generowaniu alternatywnych rozwiązań przez nawracanie

35 Posłużmy się przykładem. Mamy predykat stwierdzający ile rodziców ma dana osoba. Z Biblii wiemy, że ileRodzicow( adam, 0) :- !. ileRodzicow( ewa, 0) :- !. Natomiast reszta ludzi: ileRodzicow(X,2).

36 Jeżeli zapytamy ileRodzicow( ewa, X), otrzymamy X=0. Jeżeli zapytamy ileRodzicow( robert, X), otrzymamy X=2. Jednak jeśli chcemy sprawdzić, czy Ewa ma dwoje rodziców, to zapiszemy ileRodzicow(ewa,2).

37 I tu wyskakuje zonk. Okazuje się, że Ewa ma 2 rodziców. Dlaczego? Jest to konsekwencja sposobu przeszukiwania bazy przez Prolog. Jednak można temu zaradzić.

38 ileRodzicow( adam, N) :- !, N=0. ileRodzicow( ewa, N) :- !, N=0. ileRodzicow( X, 2). albo ileRodzicow( adam, 0) :- !. ileRodzicow( ewa, 0) :- !. ileRodzicow( X, 2) :- \+(X= adam), \+(X= ewa).

39 Załóżmy, że mamy bazę wiedzy postaci: student(1, Ewelina, 23). student(2, Robert, 40). student(3, Zuza, 20).

40 Do odczytu z klawiatury służy predykat read. Do naszej bazy zdefiniujmy relację czytaj(X) :- read(D), student(D, X)., polegającą na odczytaniu numeru studenta i pokazaniu jego danych.

41 Do wypisywania na ekran służy predykat write. Do naszej bazy zdefiniujmy relację pisz(X) :- student( X, Y), write(Y). polegającą na wypisaniu na ekran danych studenta o numerze X.

42 czytajzPliku :- open(sciezka_do_pliku',read,X), current_input(W), set_input(X), czytajKod, close(X), set_input(W). czytajKod :- read(T), write(T).

43 czytajzPliku :- open(sciezka_do_pliku', read, X), //otworzenie pliku current_input(W), //zapis strumienia wejścia do W set_input(X), //zmiana wejścia na X czytajKod, //wykonanie czytajKod close(X), //zamknięcie wejścia X set_input(W). //zmiana wejścia na W czytajKod :- read(T), write(T).

44 Domyślnym strumieniem wejściowym jest klawiatura. Jednakże czytajKod odczytuje tylko jeden wiersz z pliku. Aby odczytywać ich więcej należy go lekko zmodyfikować. czytajKod :- read(T), wykonaj(T). wykonaj( end_of_file ) :- !. wykonaj(T) :- write(T), nl, czytajKod. // nl- nowa linia

45 piszdoPliku :- open(sciezka_do_pliku',write,X), current_output(W), set_output(X), piszKod, close(X), set_output(W). piszKod :- write(T), nl.

46 piszdoPliku :- open(sciezka_do_pliku',write,X), //otworzenie pliku current_output(W), //zapis aktualnego wyjścia do W set_output(X), //zmiana aktualnego wyjścia na X piszKod, //wykonanie piszKod close(X), //zamkniecie wyjścia X set_output(W). //zmiana wyjścia na W piszKod :- write(T), nl.

47 Domyślnym strumieniem wyjściowym jest ekran. Oczywiście można zmodyfikować piszKod tak, aby końcem zapisu było wpisanie pa: piszKod :- read(X), \+(X=pa'), write(X), nl, flush, PiszKod. //flush czyści bufor

48 Predykaty wbudowane możemy podzielić na kilka kategorii, m.in.: Sukces i porażka Klasyfikacja termów Wpływ na nawracanie Równość Wejście i wyjście Obsługa plików Arytmetyka Porównanie I wiele, wiele innych …

49 Do tych predykatów zaliczamy: true – ten cel nigdy nie zawodzi. Nie jest on niezbędny, gdyż klauzury i cele można tak ustawić, żeby był zbędny. Jednak dla wygody go zdefiniowano. fail – ten cel zawsze zawiedzie. Przydatny w parze z odcięciem albo gdy chcemy jawnie wywołać nawracanie.

50 var(X) – nie zawodzi, gdy X jest zmienną nieukonkretnioną nonvar(X) – przeciwieństwo var(X) atom(X) – nie zawodzi, jeśli X jest atomem number(X) – nie zawodzi, jeśli X jest liczbą atomic(X) – nie zawodzi, jeśli X jest liczbą lub atomem

51 integer(X) – jest spełniony, jeśli X jest stałą lub zmienną całkowitą real(X) – jest spełniony, jeśli X jest stałą lub zmienną stałoprzecinkową

52 repeat – to dodatkowa metoda generowania wielu rozwiązań przez nawracanie ! – na odcięcie można patrzeć jako na predykat wbudowany zatwierdzający pewne wybory dokonane przez interpreter.

53 X=Y – gdy Prolog napotyka taki cel, stara się zrównać X z Y dopasowując je do siebie. Jeśli to możliwe, to cel jest uzgodniony, w przeciwnym wypadku zawodzi. X==Y – powoduje on lepsze zrównanie X i Y. Jeśli X==Y, to X=Y, ale nie odwrotnie.

54 get_char(X) – nie zawodzi, jeśli X można dopasować do następnego znaku z bieżącego strumienia wejściowego. Może być uzgodniony tylko raz! read(X) – odczytuje term z bieżącego strumienia wejściowego i dopasowuje go do X. Musi kończyć się kropką.

55 put_char(X) – wpisuje do bieżącego strumienia wyjściowego znak X nl – wpisuje do bieżącego strumienia wyjściowego sekwencję powodującą przejście do nowego wiersza. write(X) – powoduje zapisanie termu X do bieżącego strumienia wyjściowego.

56 open(X,Y,Z) – otwiera plik o nazwie X. Jeśli Y jest read, to w trybie odczytu, w przeciwnym razie w trybie zapisu. Z oznacza strumień, do którego należy używać podczas odwoływania się do pliku close(X) – używany do zamknięcia strumienia X

57 set_input(X) – ustawia bieżący strumień wejściowy na wskazany przez X set_output(X) – ustawia bieżący strumień wyjściowy na wskazany przez X current_input(X) – cel jest uzgodniony, jeśli nazwa bieżącego strumienia wejściowego pasuje do X. W przeciwnym razie zawodzi current_output(X) - cel jest uzgodniony, jeśli nazwa bieżącego strumienia wyjściowego pasuje do X. W przeciwnym razie zawodzi

58 X is Y X + Y X - Y X * Y X / Y X mod Y Pozostawię to bez omówienia

59 X = Y X < Y X > Y X >= Y X =< Y To również pozostawię bez omówienia

60 Zasady decydujące, które z termów są mniejsze: Wszystkie zmienne nieukonkretnione są mniejsze od wszystkich liczb zmiennoprzecinkowych. Te natomiast są mniejsze od wszystkich liczb całkowitych, które są mniejsze od wszystkich atomów, które są mniejsze od jakichkolwiek struktur

61 Zasady decydujące, które z termów są mniejsze: W przypadku dwóch niepowiązanych, nieukonkretnionych zmiennych zawsze jedna z nich będzie mniejsza od drugiej Porównywanie liczb zmiennoprzecinkowych i całkowitych odbywa się zawsze zgodnie z intuicją

62 Zasady decydujące, które z termów są mniejsze: Atom jest mniejszy od innego, jeśli występuje przed nim w zwykłym porządku słownikowym Jedna struktura jest mniejsza od drugiej, jeśli jej funktor ma mniej argumentów. Jeśli dwie struktury mają tyle samo argumentów, to mniejsza jest ta, której funktor jest mniejszy. Jeśli dwie struktury mają tyle samo argumentów i takie same funktory, to bada się po kolei pierwszy z pierwszym, drugi z drugim itd.

63 Y – nie zawodzi, jeśli X jest mniejszy od Y w porządku opisanym na poprzednich slajdach. Y – nie zawodzi, jeśli X jest większy od Y w porządku opisanym na poprzednich slajdach. Y – nie zawodzi, jeśli X jest większy lub równy Y w porządku opisanym na poprzednich slajdach. Y – nie zawodzi, jeśli X jest mniejszy lub równy Y w porządku opisanym na poprzednich slajdach.

64

65


Pobierz ppt "Term to: stała, zmienna, struktura. Każdy term zapisywany jest jako ciąg znaków, tworzących cztery kategorie: duże litery: A-Z małe litery: a-z cyfry:"

Podobne prezentacje


Reklamy Google