|
|
pl:prolog:prolog_lab:programy [2017/07/17 10:08] 127.0.0.1 edycja zewnętrzna |
pl:prolog:prolog_lab:programy [2019/06/27 15:50] |
====== LAB: Pisanie programów w Prologu ====== | |
| |
===== -. Interakcja z programem ===== | |
| |
==== Wypisywanie na wyjściu ==== | |
| |
Predykat //write/1// wypisuje term na wyjście; //nl/0// przechodzi do nowej linii. | |
| |
**Ćwiczenie** | |
| |
Przetestować działanie: | |
| |
write('Ala ma '),write('kota'),nl,write('w ciapki!'). | |
| |
| |
==== Programy interaktywne ==== | |
| |
Predykat read/1 pozwala na pobieranie danych od użytkownika. | |
| |
| |
**Ćwiczenie** | |
| |
Proszę oglądnąć zastosowanie //read/1// na przykładzie programu {{interac.pl}} | |
| |
Po załadowaniu proszę wpisać: | |
| |
?- go. | |
| |
| |
===== -. Wymuszanie nawrotów ===== | |
| |
Predykat //fail/0// pozwala na wymuszanie nawrotów w procesie poszukiwania rozwiązania, co pozwala w szczególności na znalezienie wszystkich rozwiązań problemu. | |
| |
Przypomnienie: Prolog używa strategii przeszukiwania wgłąb drzewa rozwiązań problemu i zatrzymuje sie po napotkaniu 1. poprawnego rozwiązania. | |
| |
**Ćwiczenie** | |
| |
Pobrać i wczytać program {{fam2.pl}} | |
| |
Wyświetlić go przez listing. | |
| |
Sprawdzić działanie: | |
| |
?- kobieta(K),write(K),write(' to kobieta.'),nl. | |
| |
Jak wymusić odnajdywanie kolejnych kobiet. | |
| |
Sprawdzić działanie: | |
| |
?- kobieta(K),write(K),write(' to kobieta.'),nl,fail. | |
| |
Sprawdzić działanie: | |
| |
?- kobieta(K),fail. | |
| |
Dlaczego nic się nie pojawia? | |
| |
Pobrać i wczytać program {{capitals.pl}} | |
| |
Sprawdzić działanie: | |
| |
?- capital_of(A,B), write(B), write(' to stolica '), write(A), nl. | |
?- capital_of(A,B), write(B), write(' to stolica '), write(A), nl, fail. | |
| |
| |
===== -. Dynamiczna bazy wiedzy ===== | |
| |
==== Modyfikacja bazy wiedzy ==== | |
| |
Predykaty //assert/a/z /1//, //retract/a/z /1// pozwalają na dodawanie, usuwanie faktów do/z bazy wiedzy, na/do jej początku/końca. | |
| |
Predykat //abolish/1// pozwala usunąć predykat z bazy wiedzy. (np. ''abolish(kobieta/1).'') | |
| |
Predykat //retractall/1// pozwala usunąć klauzule danego predykatu z bazy wiedzy. (np. ''retractall(kobieta(K)).'') | |
| |
Predykaty //see/n//, //tell/told// pozwalają na odczyt, zapis bazy wiedzy z/do pliku. | |
| |
**Ćwiczenie** | |
| |
Proszę napisać: | |
| |
?- assert(kobieta(kopernik)). | |
| |
jak zmieniła sie wiedza na temat kobiet? | |
| |
?- listing(kobieta). | |
| |
Proszę sprawdzić: | |
| |
kobieta(K),write(K),write(' to kobieta.'),nl,fail. | |
| |
Uwaga: niektóre kompilatory Prologu (np. SWI) wymagają wcześniejszego zadeklarowania predykatu jako takiego, który może być dynamicznie modyfikowany. Robi się to przez predykat //dynamic/1//, np. dla predykatu //kobieta/1// deklaracja w pliku //fam2.pl// ma postać '':- dynamic(kobieta/1).''. | |
| |
Proszę oglądnąć zastosowanie //assert/retract// na przykładzie programu {{learner.pl}} | |
| |
Początkowa baza wiedzy jest w pliku {{learner_kb.pl}} | |
| |
Należy uruchomić program przez ''start.'' | |
| |
Jakie 3 przypadki odpowiedzi są brane pod uwagę? Co dzieje się przy wyjściu z programu i jak to wpływa na jego kolejne uruchamianie? | |
| |
Uwaga: operator ''\+'' oznacza //negację//. | |
| |
Predykat //dynamic/1// jest potrzebny w niektórych implementacjach Prologu (np. SWI) do umożliwienia wykonywania dynamicznych modyfikacji, t.j. //assert// i //retract//. | |
| |
| |
==== Modyfikacja reguł ==== | |
| |
assert/retract pozwala również dodawać/usuwać reguły: | |
| |
<code prolog> | |
:-dynamic(a/1), dynamic(b/2). | |
| |
a(1). a(2). | |
| |
addrule:- assert((b(X,Y):-a(X),a(Y))). | |
| |
delrule:- retract((b(_,_):-_)). | |
| |
start:-addrule, b(X,Y), write(X), write(' '), write(Y),nl,fail. | |
start. | |
</code> | |
| |
W powyższym programie predykat ''addrule/0'' dodaje (''delrule/0'' usuwa) dynamicznie regułę: | |
<code> | |
b(X,Y):-a(X),a(Y). | |
</code> | |
| |
| |
===== -. Zadawanie celu ===== | |
| |
Konstrukcja: | |
| |
:- cos. | |
| |
pozwala na podanie celu w programie, np.: | |
| |
:- dynamic(capital_of/2). | |
:- go. | |
:- start. | |
| |
Prolog przystąpi do zrealizowania celu po załadowaniu kodu. | |
| |
Uruchomienie programu ze wskazanego pliku (''plik.pl'') z poziomu systemu operacyjnego można zrealizować za pomocą: | |
| |
swipl -s program.pl -g go -t halt | |
| |
===== -. Śledzenie pracy programu ===== | |
| |
Interpretery Prologu pozwalają na śledzenie pracy programu. W tym celu należy ustawić tzw. trace point. | |
| |
Trace points: | |
* trace/0 - ustawia trace point na wszystkich predykatach, w wersji swi-prolog używanej na laboratorium, ''trace/0'' śledzi **następny zadany cel**, np. | |
<code prolog> | |
?- trace,kobieta(K),rodzic(K,_). | |
</code> | |
* trace/1 - ustawia trace point na wskazanym predykacie, | |
* trace/2 - modyfikuje dla wskazanego predykatu śledzone zdarzenia (call, redo, exit, fail), np.: | |
* trace(something/1,-all) - zdejmuje trace point ze wskazanego predykatu //something/1//, | |
* trace(something,+call) - ustawia trace point śledzący jedynie wywołania na wskazane predykaty //something// o dowolnej arności. | |
| |
Predykat //debugging/0// wypisuje ustawione trace points. | |
Predykat //debug/0// wchodzi do trybu debug. | |
Predykat //nodebug/0// wychodzi z trybu debug. | |
| |
**Ćwiczenie** | |
| |
Pobrać i wczytać program {{fam2.pl}} | |
| |
Sprawdzić działanie: | |
| |
<code prolog> | |
?- trace(matka). | |
[debug] ?- matka(kasia,robert). | |
[debug] ?- ojciec(tomek,robert). | |
[debug] ?- nodebug. | |
?- matka(kasia,robert). | |
?- debug. | |
[debug] ?- trace(matka,-all). | |
[debug] ?- matka(kasia,robert). | |
[debug] ?- trace(matka,+call). | |
[debug] ?- matka(kasia,robert). | |
[debug] ?- nodebug. | |
?- trace. | |
[debug] ?- matka(kasia,robert). | |
[debug] ?- nodebug. | |
</code> | |
| |
W SWI Prologu można też skorzystać z dodatkowego pakietu XPCE, w którym jest też wizualny debugger. | |
| |
Należy wyjść z bieżacej sesji SWI. Uruchomić interpreter z powłoki unixa przez przez polecenie ''xpce''. Następnie uruchomić graficzny tracer przy użyciu predykatu guitracer/0. | |
| |
===== -. Arytmetyka w Prologu ===== | |
| |
W Prologu nie można w sposób //bezpośredni// wykonywać obliczeń arytmetycznych. Służy do tego predykat //is//. | |
| |
| |
**Ćwiczenie** | |
| |
1. Sprawdzić działanie: | |
| |
<code prolog> | |
?- X is 2 + 2. | |
?- Y is 2.5 + ( 4 / 2). | |
?- Z is 2 + 0.001. | |
</code> | |
| |
Uwaga: | |
| |
<code prolog> | |
?- A is 3. | |
?- B is A + 4. | |
?- A is 3, B is A + 4. | |
</code> | |
| |
Operacje arytmetyczne: | |
| |
<code prolog> | |
?- X is 2 + 2. | |
?- X is 2 * 3. | |
?- X is 4 / 2. | |
?- X is 4 / 3. | |
?- X is 4 // 3. | |
</code> | |
Uwaga na //podstawianie//: | |
| |
<code prolog> | |
?- X is 2 + 5. | |
?- X = 2 + 5. | |
?- 2 + 5 =:= 1 + 4. | |
?- 2 + 5 =:= 3 + 4. | |
?- 2 + 5 =:= 4 + 4. | |
</code> | |
| |
Przećwiczyć użycie operatorów: | |
| |
<code prolog> | |
?- 2 < 3. | |
?- 2 > 3. | |
?- 3 > 3. | |
?- 3 >= 3. | |
?- 3 =< 3. | |
</code> | |
| |
2. Napisz program obliczający wynik [[http://pl.wikipedia.org/wiki/R%C3%B3wnanie_kwadratowe|równania kwadratowego]] ([[wp>Quadratic Equation]]) ''ax^2 + bx + c = 0'' w dziedzinie liczb rzeczywistych. | |
Zaimplementuj predykaty: | |
* ''delta/4'' -- obliczający deltę, argumenty kolejno: a, b, c, wynik, | |
* ''kwadrat/4'' -- obliczający wynik równania kwadratowego, argumenty kolejno: a, b, c, wynik. | |
Zwróć uwagę na niedeterminizm w predykacie ''kwadrat/4'', który znajduje zero, jedno, albo dwa rozwiązania; mogą się przydać [[http://www.swi-prolog.org/pldoc/doc_for?object=section%282%2c%20%274.25%27%2c%20swi%28%27%2fdoc%2fManual%2farith.html%27%29%29|funkcje matematyczne]], w szczególności do obliczenia pierwiastka używa się ''sqrt/1''. | |
| |
| |
===== -. Rekurencja w Prologu ===== | |
| |
Typowym przykładem wykorzystania mechanizmu rekurencji jest obliczanie wartości funkcji silnia. | |
Poniżej znajduje się kod realizujący tą funkcjonalność. | |
| |
<code prolog> | |
factorial(0,1). | |
factorial(Number,Result) :- | |
Number > 0, | |
NewNumber is Number-1, | |
factorial(NewNumber,NewResult), | |
Result is Number*NewResult. | |
</code> | |
| |
| |
**Ćwiczenie** | |
| |
Wpisz, przetestuj i przemyśl działanie programu rekurencyjnie liczącego silnię. | |
Uruchom program w trybie śledzenia wykonywania (trace). | |
| |
**Ćwiczenie** | |
| |
Opierając się na silni napisz program wypisujący [[http://pl.wikipedia.org/wiki/Ci%C4%85g_Fibonacciego|Ciąg Fibonacciego]]. | |
| |
===== - Wybrane problemy rozwiązane w Prologu ===== | |
| |
==== Świat klocków ==== | |
Problem [[wp>Blocks_world]] | |
| |
Wczytaj {{:pl:prolog:prolog_lab:blocks.pl|}} | |
| |
Narysuj na kartce zamodelowany świat. | |
Jakie pytania można zadać? | |
<code prolog> | |
above(b1,b2). | |
above(b3,b5). | |
left(b1,b7). | |
left(b3,b3). | |
</code> | |
| |
| |
**Ćwiczenie** | |
| |
Opisz w programie taki świat: | |
<code> | |
a1 | |
a2 | |
a3 c1 c3 | |
a4 a5 c2 c4 | |
</code> | |
| |
==== Wieże Hanoi ==== | |
Problem [[http://pl.wikipedia.org/wiki/Wieże_Hanoi]]. | |
| |
Problem [[wp>Towers_of_hanoi]] | |
| |
**Ćwiczenie** | |
| |
Proszę pobrać program {{:pl:prolog:prolog_lab:hanoi.pl|hanoi.pl}}. | |
Przetestować i przemyśleć. | |
| |
Predykat //move/4// działa następująco:\\ | |
np. //move(3,left,right,center)// przenosi 3 krążki ze stosu //left// na stos //right// przy pomocy stosu //center//. | |
| |
Przykład: | |
<code prolog> | |
?- move(3,left,right,center). | |
Move top disk from left to right | |
Move top disk from left to center | |
Move top disk from right to center | |
Move top disk from left to right | |
Move top disk from center to left | |
Move top disk from center to right | |
Move top disk from left to right | |
</code> | |
| |
Analizując kod programu proszę zauważyć, że algorytm rozwiązania problemu opiera się na dekompozycji na podproblemy. | |
| |
==== Kolorowanie Mapy ==== | |
Problem: mamy mapę taką jak poniżej | |
| |
<code prolog> | |
| |
|Bialorus | |
|------------ | |
Polska | | |
---------------| | |
| | Ukraina | |
Czechy| Slowacja|----------- | |
----------------- | |
</code> | |
| |
Należy ja pokolorować 3 kolorami, tak aby żadne sąsiadujące państwa nie miały takiego samego koloru: | |
[[wp>Four_color_theorem]] | |
| |
| |
**Ćwiczenie** | |
| |
Definiujemy 3 kolory: | |
| |
<code prolog> | |
kolor(czerwony). | |
kolor(zielony). | |
kolor(niebieski). | |
</code> | |
| |
Należy zdefiniować predykat ''koloruj/5'', tak aby zadając pytanie: | |
| |
?- koloruj(Polska,Bialorus,Ukraina,Slowacja,Czechy). | |
| |
dostać wszystkie możliwości pokolorowania tej konkretnej mapy. | |
| |
Uwaga: predykat ''koloruj/5'' definiuje zależności geograficzne. | |
| |
Uwaga: w Prologu operator ''\='' to nieidentyczność, czy też niemożliwość uzgodnienia termów. | |
| |
==== Dla Zainteresowanych ==== | |
Więcej ciekawych problemów [[reprezentacja_wiedzy#ciekawe_problemy|na kolejnych zajęciach]] | |
oraz w [[prolog:pllib:start|bibliotece programów]]. | |
| |
===== Obserwacje ===== | |
| |
W Prologu negacja opiera się o //Closed World Assumption//! | |
| |
W Prologu nie ma dualizmu "dane/kod" -> w Prologu jest jedna //baza wiedzy//, zawierająca fakty i reguły, którą można dynamicznie modyfikować. | |
| |
===== Komentarze ===== | |
Z braku lepszego miejsca tutaj studenci wpisują komentarze natury ogólnej do tego lab. 8-) | |
| |
--- //[[gjn@agh.edu.pl|Grzegorz J. Nalepa]] 2008/02/20 14:34// | |