Pobierz prezentację
Pobieranie prezentacji. Proszę czekać
OpublikowałMaciej Wojciechowski Został zmieniony 9 lat temu
1
Rozdział IV Wyrażenia proceduralne algorytmów Grzegorz Gacek Patryk Gajewski
2
Proceduralny Prolog Jak wiemy Prolog łączy programowanie proceduralne z nieproceduralnym. W tym rozdziale omówimy język programowania, jakim jest Prolog, od strony proceduralnej. Przedstawione zostaną programy przekształcone z innych języków na Prolog. Przez niektórych uważane jest, że Prolog nie powinien zawierać programowanie proceduralnego. Jednak ze jest to niewłaściwe podejście. Prolog powinien być kompromisem programowanie nieproceduralnego z proceduralnym.
3
Wyrażenia warunkowe Istotną różnicą pomiędzy Prologiem, a innymi językami programowania jest to ze procedury w Prologu mogą mieć wiele definicji, a każda być stosowana w różnych warunkach. W Prologu wyrażenia warunkowe są zwykłymi zależnościami i w przeciwieństwie do programowania proceduralnego nie trzeba stosować IF ani CASE, ale inne definicje procedur.
4
Przykład wypisywania nazw liczb: PascalProlog procedure writename(X:integer); Begin case X ofwritename(1) :- write(‘One’). 1:write(‘One’);writename(2) :- write(‘Two’). 2:write(‘Two’):writename(3) :- write(‘Three’). 3:write(‘Three’) end end;
5
Kluczem do efektywnego programowania w Prologu jest uczynienie każdej logicznej jednostki programu jako osobną procedurę. Każda decyzja, która klauzula powinna być wykonana powinna być podejmowana w trakcie działania procedury. Za każdym razem jak ma być podjęta decyzja, Prolog wywołuje procedury i wybiera właściwą klauzule do wykonania.
6
Operator CUT Wróćmy do przykładu wypisywania nazw liczb. A o gdybyśmy chcieli, aby program wypisywał, że wyszliśmy poza zakres w przypadku podania nieuwzględnionej liczby? writename(1) :- write(‘One’). writename(2) :- write(‘Two’). writename(3) :- write(‘Three’). writename(X) :- X<1, write(‘Out of range’). writename(X) :- X>3, write(‘Out of range’). Jest to poprawny przykład, ale brakuje mu zwięzłości. Program aby powiedzieć, że liczba jest z poza przedziału musi przetestować dwie ostanie klauzule.
7
Spróbujmy inaczej: writename(1) :- write(‘One’). writename(2) :- write(‘Two’). writename(3) :- write(‘Three’). writename(_) :- write(‘Out of range’). Sposób ten jest niewłaściwy, ponieważ weźmy na przykład zapytanie ?-writename(1). Wypisze nam zarówno „One” jak i „Out of range” gdyż do obu będzie pasować.
8
Z pomocą przychodzi nam operator cut, pisany przy pomocy znaku wykrzyknika -! Pozwala on na zablokowanie procesu nawrotu w wybranym miejscu. W efekcie można uniknąć wyszukiwania niechcianych, zbędnych, a czasem wręcz niepoprawnych rozwiązań. Oto oprawiony przykład: writename(1) :-!, write(‘One’). writename(2) :-!, write(‘Two’). writename(3) :-!, write(‘Three’). writename(_) :- write(‘Out of range’).
9
Red Cuts and Green Cuts Red Cuts- są to odcięcia dodawane w celu ograniczenia zbioru rozwiązań. Green Cuts- odcięcia dodawane w celu poprawienia wydajności programu.
10
Przykład wypisywania nazw liczb z użyciem green cut: writename(1) :- !, write(‘One’). writename(2) :- !, write(‘Two’). writename(3) :- !, write(‘Three’). writename(X) :-X<1, !, write(‘Out of range’). writename(X) :-X>3, write(‘Out of range’). Dzięki temu wyeliminowaliśmy nawracanie.
11
Przykład wypisywania nazw liczb z użyciem red cut: writename(1) :-!, write(‘One’). writename(2) :-!, write(‘Two’). writename(3) :-!, write(‘Three’). writename(_) :- write(‘Out of range’). Pozwala nam to na zaoszczędzenie czasu gdyż jeśli X=1 wykonana zostanie pierwsza klauzula, a reszta nigdy nie zostanie wykonana.
12
Alternatywa dla CUT Alternatywą dla operatora odcięcia jest predykat once(). Zastosowanie tego predykatu spowoduje podanie pierwszego rozwiązania naszego wyrażenia, nie szukając dalszych alternatyw. Zatem dla: writename(1) :- write(‘One’). writename(2) :- write(‘Two’). writename(3) :- write(‘Three’). Użycie ?- once(writename(X)). Spowoduje wypisanie tylko pierwszej opcji.
13
Struktura IF-THEN-ELSE Inną możliwością osiągnięcia deterministycznych wyborów w Prologu jest użycie struktury if-then-else. Składnia jest następująca: Cel1 -> Cel2 ; Cel3. Co można przeczytać w następujący sposób: Jeśli Cel1 jest prawdą to wykonaj Cel2, jeśli nie to wykonaj Cel3. Przykład: writename(X) :- X = 1 -> write(‘One’) ; write(‘not one’). Co można przetłumaczyć: jeśli X jest równy 1 to napisz,one’ jeśli nie to napisz,not one’.
14
Strukturę if-then-else możemy zagnieżdżać: write(X) :- ( X = 1 -> write(‘one’) ; X = 2 -> write(‘two’) ; X = 3 -> write(‘three’) ; write(‘out of range’)).
15
Zawsze prawda lub zawsze fałsz Czasami w celu zachowania wykonywania programu koniecznie jest zagwarantowanie, że cel uda się niezależnie od wyników obliczenia. Na przykład: g(X,Y) :- X<Y, write(X’ less than Y’), !, true. g(X,Y) :- X<Y, write(‘Y less than X’), !, fail. Zapytanie ?- g(2,3). Zwróci „X less than Y” oraz true, a zapytanie ?- g(2,4). Zwróci „Y less than X” oraz false mimo ze jest to prawda.
16
Powtarzanie poprzez nawracanie Predykat repeat służy do wymuszenia poszukiwania kolejnych rozwiązań. Jest to predykat, który zawsze się powodzi i wymusza „Zmianę kierunku” podczas nawracania. Przykład zastosowania predykatu repeat: typewriter :- repeat, get0(C), C = 115. Po wprowadzeniu ?- typewriter. Program będzie powtarzał się dopóki nie osiągnie wartości true, w tym przykładzie nie przerwie się dopóki nie wciśnięty zostanie klawisz s.
17
W związku z tym, że predykat repeat zawsze zwraca true, to użycie razem z predykat fail wymuszającym zwrócenie fail, pozwoli na stworzenie nieskończonych pętli: ?-repat, write(‘*’),fail.
18
Pętle rekurencyjne Rekurencja to wywołanie jakiejś metody przez samą siebie. W pewnym miejscu następuje ponowne wywołanie siebie od początku. Gdybyśmy nie przerwali rekurencji, trwałaby ona w nieskończoność. Przykład rekurencji obliczającej potęgi liczb od 1 do 5: print_squares(I) :- I > 5, !. print_squares(I) :- S is I*I, write(I), write(‘ ‘), write(S), ni, NewI is I+1, print_squares(NewI).
19
Zasady poprawnej organizacji kodu rekursywnego Określenie warunku zakończenia i kontynuacji pętli Poprawnie działająca pętla rekursywna: Rozpoczyna się w poprawnym miejscu Kończy się w poprawnym miejscu Poprawnie przechodzi z jednego stanu do drugiego
20
Tail recursion Jest to rodzaj rekurencji gdzie ostatnia operacja ma na celu wywołanie samej siebie lub zwrócenie wyniku końcowego. Taka rekurencja może być wykonana przy pomocy zwykłych funkcji. Później w razie potrzeby można taką funkcję zamienić na iterację. Ale trzeba pamiętać, że niewłaściwe użycie tego może doprowadzić do przepełnienia się stosu. Przykład: test1(N) :- write(N), nI, NewN is N+1, test1(NewN). Funkcja w ostatniej operacji wywołuje siebie samą.
21
Indeksowanie Indeksowanie pozwala Prologowi na znalezienie od razu szukanego predykatu bez przeszukiwania całej bazy danych. Indeksowanie może bardzo przyspieszyć zapytania. Może również stworzyć zapytania, które mają rekursję w ogonie, gdy w inny sposób nie da się ich uzyskać. Przykład: test8(0) :- write(‘Still going’), nl, test8(0). test8(-1). Wykonanie zapytania ?- test8(0). Spowoduje rekurencyjne wykonanie ogona w związku z czym druga klauzula nigdy się nie wykona. Zapytanie ?-test8(-1). Przejdzie od razu do drugiej klauzuli nie wykonując pierwszej.
22
Dziękujemy za uwagę !!! :D
Podobne prezentacje
© 2024 SlidePlayer.pl Inc.
All rights reserved.