{{header>2}}
====== - LAB: Metaprogramowanie w Prologu ======
===== - Temat: Sprawdzanie typów termów =====
Prolog dostarcza szeregu predykatów, pozwalających na analizowanie typów termów.
Po pierwsze można stwierdzić, czy term jest niewiadomą (zmienną logiczną) o nieustalonej wartości, czy też ma określoną wartość, czyli jest stałą, lub zmienną o wcześniej ustalonej wartości (po pomyślnej unifikacji).
Służą do tego predykaty:
var(X).
nonvar(X).
Poza tym, jest szereg predykatów sprawdzających, czy term jest:
atom
atomem logicznym (stałą, napisem)
atomic
liczbą lub atomem
number
liczbą
compound
złożoną strukturą
integer
liczbą całkowitą
float
liczbą zmiennoprzecinkową
** Ćwiczenie:**
Proszę przetestować poniższe:
?- var(X).
?- var(X),X=2.
?- X=2,var(X).
?- atom(X).
?- atom(3).
?- atom(a).
?- atom(+).
?- atom(:=).
?- atom('ala').
?- atomic(a).
?- atomic(3).
?- atomic(+).
?- atomic(X).
?- number(ala).
?- number(3).
?- integer(3).
?- integer(3.14).
?- float(3).
?- float(3.14).
?- compound(ala).
?- compound(ala(ma,kota)).
?- compound(3).
Uwaga: ''compound'' nie nadaje się do "wykrywania" list, bo:
?- compound([]).
===== - Temat: Konstruowanie i dekompozycja termów =====
Z racji tego, iż termy sa podstawową metodą strukturalizacji danych w Prolog, istnieje kilka mechanizmów wspomagających ich przetwarzanie:
=..
operator pozwala na dynamiczną zamianę termu na listę i vice versa
functor(T,N,A)
predykat jest prawdziwy, jeżeli N pokrywa się z nazwą termu T o arności A
arg(N,T,A)
predykat jest prawdziwy, jeżeli A jest Ntym argumentem termu T
** Ćwiczenie:**
Proszę przećwiczyć przetwarzanie termów:
?- A =.. [ala, ma, asa].
?- ala(ma,kota,w(ciapki(rozowe))) =.. A.
Przeanalizować:
?- functor(ala(ma,kota),F,A).
?- CzyTo = ala, OLiczbie = 2, functor(ala(ma,kota),CzyTo,OLiczbie).
?- CzyTo = kasia, OLiczbie = 2, functor(ala(ma,kota),CzyTo,OLiczbie).
?- functor(ala(ma,kota),F,_), write('To jest funktor \''), write(F), write('\'.').
?- arg(X,ala_ma(kota,psa,schiza),A).
?- arg(2,ala_ma(kota,psa,schiza),A).
?- functor(A,riverside,3).
?- functor(A,riverside,4), arg(1,A,voices), arg(4,A,head).
Poniższy kod (predykaty ''wyp0/2'', ''wyp1/2'', ''wyp2/2'', ''wyp3/2'') prezentuje sposoby odwoływania się do predykatów przekazywanych jako argumenty.
Przykłady użycia znajdują się w części dalszej.
a(1). a(2). b(4). b(3).
wyp0(F,_) :-
call(F).
wyp1(F,X) :-
F,
F =.. [_,X].
wyp2(F,X) :-
functor(Pred,F,1),
Pred,
Pred =.. [_,X].
wyp3(F/A,X) :-
A = 1,
functor(Pred,F,A),
Pred,
Pred =.. [_,X].
Wykonaj zapytania będące przykładami użycia powyższych predykatów:
?- wyp0(a(X),X).
?- wyp0(b(X),X).
?- wyp1(a(_),X).
?- wyp1(b(_),X).
?- wyp2(a,X).
?- wyp2(b,X).
?- wyp3(a/1,X).
?- wyp3(b/1,X).
===== - Temat: Definiowanie operatorów =====
W prologu bardzo łatwo można definiować własne operatory, co ułatwia przetwarzanie danych.
Realizowane jest to przez predykat :- op(P, T, N), który definiuje N, jako operator typu T, o priorytecie P.
Zobacz:
* http://www.swi-prolog.org/pldoc/man?predicate=op/3
* http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse40
Zdefiniowane w standardzie ISO operatory to:
1200 xfx -->, :-
1200 fx :-, ?-
1150 fx dynamic, discontiguous, initialization, module_transparent, multifile, thread_local, volatile
1100 xfy ;, |
1050 xfy ->, op*->
1000 xfy ,
954 xfy \
900 fy \+
900 fx ~
700 xfx <, =, =.., =@=, =:=, =<, ==, =\=, >, >=, @<, @=<, @>, @>=, \=, \==, is
600 xfy :
500 yfx +, -, /\, \/, xor
500 fx +, -, ?, \
400 yfx *, /, //, rdiv, <<, >>, mod, rem
200 xfx **
200 xfy ^
Wszystkie mogą być zredefiniowane!.
Gdyby nie operatory, to prosty program w Prologu:
go :- write('Hello '), write('World\n').
:- go.
Musialby wyglądać następująco (wszytko w notacji prefiksowej, zapisane jako termy):
:- (go,','(write('Hello '), write('World\n'))).
:- (go).
Uwaga: obydwa programy są równoważne. W drugim programie widać, że klauzule złożone również zapisane są jako termy.
Patrz również:
* [[http://cs.union.edu/~striegnk/learn-prolog-now/html/node84.html#subsec.l9.operators.def|Lean Prolog Now]]
** Ćwiczenie: **
Proszę wpisać do pliku oper1.pl
:- op(100,xfy, matka).
julia matka marcin.
a nastepnie przetestować:
?- X matka Y.
Dopisać do pliku:
:- op(300, xfx, ma).
:- op(200, xfy, i).
jas ma kota i psa.
ala ma jasia i angine i dosc_agh.
rybki i kanarki.
Przetestować:
?- ma(X,Y).
?- ma(X,i(A,B)).
?- ma(A,i(B,i(C,D))).
?- Kto ma Co.
?- Kto ma Co i Cosinnego.
?- Kto ma Cos i CosInnego i Jeszcze.
?- display(jas ma kota i psa).
?- display(ala ma jasia i angine i dosc_agh).
Co zwróci poniższe zapytanie?
?- i(A,B).
Podpowiedź: zwróć uwagę na priorytety operatorów.
===== - Temat: Konstruowanie klauzul i Metainterpretery =====
W Prologu występują dwa silne mechnizmy wspomagające metainterpretację kodu:
call(X)
wywołuje X, jako cel Prologu,
clause(Head,Body)
odszukuje klauzulę o nagłówku Head, gdzie Body jest unifikowane z ciałem klauzuli; w przypadku faktów Body=true.
Meta programowanie to tworzenie programów, które przetwarzają kod innych programów. Przykłady metaprogramowania znaleźć można w np.: kompilatorach, analizatorach kodu, generatorach kodu. W Prologu metaprogramowanie jest naturalną techniką, dzięki czemu pisanie programów działających w diametralnie różnych paradygmatach jest proste.
** Ćwiczenie: **
Proszę wczytać program {{rodzina1.pl}}
Uruchomić:
?- listing(kobieta).
?- call(kobieta(X)).
?- clause(kobieta(X),B).
?- listing(matka).
?- Kto = kasia, call(matka(Kto,Kogo)), write(Kto), write(' jest matka '), write(Kogo).
?- Matka = kasia, Dziecko = robert, clause(matka(Matka,Dziecko),Kiedy), write(Matka), write(' jest matka '), write(Dziecko), write(' wtedy gdy: '), write(Kiedy).
Proszę do pliku meta.pl wpisać predykat:
:- include(readstr).
odpowiedz :-
write('\'matka\' czy \'ojciec\'? '),
read_atom(X),
write('kogo? '),
read_atom(Y),
Q =.. [X,Kto,Y],
display(Q),
call(Q),
write(Kto), nl.
Uwaga: potrzebny jest dodatkowy plik: {{readstr.pl}}
a następnie przetestować i przemyśleć:
?- odpowiedz.
'matka' czy 'ojciec'? ojciec
kogo? robert
Dopisać do pliku meta.pl następujące proste metainterpretery Prologu:
rozwiaz1(G) :- call(G).
rozwiaz2(true) :- !.
rozwiaz2((G1,G2)) :- !,
rozwiaz2(G1),
rozwiaz2(G2).
rozwiaz2(G) :-
clause(G,B),
rozwiaz2(B).
rozwiaz3(true) :-!.
rozwiaz3((G1,G2)) :- !,
rozwiaz3(G1),
rozwiaz3(G2).
rozwiaz3(G) :-
write('Wywoluje: '), write(G), nl,
clause(G,B),
rozwiaz3(B),
write('Wyjscie: '), write(G), nl.
Pierwszy z nich po prostu wywołuje pojedynczy cel, tak jak powłoka SWI.
Drugi pozwala na zadanie celu złożonego z 2 części.
Trzeci działa podobnie, ale śledzi wykonywanie.
Przetestować ich działanie:
?- rozwiaz1(matka(kasia,X)).
?- rozwiaz1((matka(kasia,X), matka(Y,robert))).
?- rozwiaz2((matka(kasia,X), matka(Y,robert))).
?- rozwiaz3((matka(kasia,X), matka(Y,robert))).
Proszę pobrać kod {{tracerdepth.pl}}
Przetestować:
?- traced(matka(kasia,Y)).
===== - Temat: Systemy ekspertowe =====
W Prologu niezwykle prosto tworzy się systemy ekspertowe.
W systemie ekspertowym można wyróżnić następujące elementy:
* baza wiedzy, czasami dzielona na: właściwą bazę wiedzy (czyli tą którą system dysponuje stale, od początku/uruchomienia) i bazę faktów, które system odkrywa, dostaje, wypracowuje,
* mechanizm wnioskujący, który przeprowadza właściwy proces wnioskowania, tj. odnajduje rozwiązanie/odpowiedź
* mechanizm wyjaśniający, dlaczego jest to odpowiedź poprawna/dopuszczalna,
* interfejs użytkownika, pozwalający na komunikację z systemem.
Rysunek 1: Struktura Systemu Ekspertowego.
{{expert-systems-arch.png}}
Poniżej podane są przykłady różnych systemów.
==== - System: CAR ====
Źródło: Michael A. Covington, Donald Nute and André Vellino, //Prolog programming in depth//, Prentice-Hall, 1996.
Cechy:
* klauzule Prologu jako reprezentacja wiedzy
* wbudowany mechanizm Prologu
* wnioskowanie wstecz (abdukcja) ((Backward chaining inference, goal driven inference - stosowane w systemach diagnostycznych, w którym mamy ograniczoną (niewielką) liczbę możliwych hipotez, system stara się dowieść każdej z nich po kolei, zbierając informacje "po drodze"))
* trywialny :-)
System: {{car.pl}}
Dodatkowo korzysta on z pliku {{getyesno.pl}}
Przetestować działanie systemu.
System diagnozuje przyczyną awarii samochodu.
W przypadku tego systemu elementy systemu ekspertowego są odwzorowane przez:
* predykat //defect_may_be/1// -> baza wiedzy
* predykat //try_all_possibilities/0// oraz mechanizm wnioskujący Prologu -> mechanizm wnioskujący
* predykat //explain/1// -> mechanizm wyjaśniania
* predykaty //ask_question/1// i //user_says/2// -> interfejs użytkownika
System: {{car.pl}}
Plik pomocniczy: {{getyesno.pl}}
==== - System: BIRDS ====
Źródło: Dennis Merritt, //[[http://www.amzi.com/ExpertSystemsInProlog/|Building Expert Systems in Prolog]]//, Springer-Verlag, 1989.
Cechy:
* prologowa reprezentacja reguł
* własny mechanizm wnioskujący - metainterpreter
* wnioskowanie wprzód ((Forward chaining inference, data driven inference - stosowane w celu uniknięcia eksplozji kombinatorycznej, gdy możliwe jest (nieskończenie) wiele poprawnych odpowiedzi, system na podstawie danych "odpala" odpowiednie reguły))
* wymienne bazy wiedzy
Mechanizm wnioskujący: {{native.pl}}
Bazy wiedzy: {{birds_kb.pl}}
Uruchomienie: załadować //native.pl// i wywołać ''main.''
==== - System: OOPS ====
Źródło: Dennis Merritt, //[[http://www.amzi.com/ExpertSystemsInProlog/|Building Expert Systems in Prolog]]//, Springer-Verlag, 1989.
Cechy:
* własna reprezentacja reguł
* kodowanie reguł na termach Prologu
* własny mechanizm wnioskujący
* wnioskowanie wprzód
* wymienne bazy wiedzy
Mechanizm wnioskujący: {{oops.pl}}
Bazy wiedzy: {{room_kb.pl}} {{animal_kb.pl}}
Uruchomienie: załadować //oops.pl// i wywołać ''main.''
==== - System: XSHELL ====
Źródło: Michael A. Covington, Donald Nute and André Vellino, //[[http://www.covingtoninnovations.com/books.html#ppid|Prolog programming in depth]]//, Prentice-Hall, 1996.
Cechy:
* klauzule Prologu jako reprezentacja wiedzy
* rozbudowana reprezentacja reguł
* wbudowany mechanizm Prologu
* wnioskowanie wstecz
* wymienne bazy wiedzy
* rozbudowane przetwarzanie
Mechanizm wnioskujący: {{xshell.pl}}
Baza wiedzy: {{cichlid.pl}}
Pliki pomocnicze: {{readstr.pl}} , {{readnum.pl}} , {{writeln.pl}} , {{getyesno.pl}}
Należy załadować plik z bazą wiedzy (ten z kolei ładuje mechanizm wnioskujący) i użyć predykatu ''xshell.''
**Ćwiczenie: **
Przetestuj powyższe systemy.
Analizując ich pracę i sposób implementacji, proszę zwrócić uwagę na:
* sposób reprezentacji reguł, jak są zapisywane reguły w bazie wiedzy systemu, z jakich operatorów korzystają,
* sposób implementacji mechanizmy wnioskującego, na jakich rozwiązaniach się opiera.
====== Temat: własne systemy ======
Zbuduj bazę wiedzy dla własnego systemu regułowego (dla wybranej implementacji).
Propozycje dziedzin podane są poniżej.
System rozpoznaje psy.
Należy opisać kilka/naście znanych ras psów na podstawie: [[http://pl.wikipedia.org/wiki/Grupy_FCI]], [[http://atlaspsow.w.interia.pl]], [[http://rasy-psow.com]], [[http://www.psy.elk.pl/rasypsow/]].
Warto wybrać przedstawicieli z różnych grup FCI.
W celu identyfikacji rasy trzeba wybrać kilka podstawowych cech, w tym płeć (powiązana z rozmiarem!), wagę, rozmiar, umaszczenie, kształt głowy, uszy, etc.
Podobny do w.w. system rozpoznający ptaki występujące w Polsce.
Należy oprzeć się na:
[[http://ptaki.luzik.proste.pl]], [[http://ptaki.zwierzeta.ekologia.pl]].
====== Uwagi, komentarze, propozycje ======
Tu studenci mogą wpisywać swoje uwagi...
--- //[[gjn@agh.edu.pl|Grzegorz J. Nalepa]] 2009/05/06 09:13//