You are on page 1of 118

PROLOG

OPERATORI, REZ
SADRŽAJ
oOperatori
oPredefinirani operatori
oVlastiti operatori
oRez
oNadogradnja zadataka
OPERATORI
Ranije smo spomenuli
aritmetičke operatore.
Prolog omogućuje da
korisnik, osim
predefiniranih operatora,
definira i svoje vlastite
operatore.
OPERATORI
Prema broju argumenata Prolog dozvoljava sljedeće vrste
operatora:
◦ unarni -7
◦ binarni 3+1
Prolog daje i mogućnost definiranja tri vrste operatora
prema položaju operanada:
◦ prefiksni -7
◦ infiksni 3+1
◦ postfiksni 8 faktorijela
S obzirom na komutativnost, operatori mogu biti:
◦ komutativni 2+3 = = 3+2
◦ nekomutativni 3-1 =\= 1-3
OPERATORI
Kod definiranja operatora, osim položaja operanada,
definira se i jačina vezivanja, odnosno redoslijed izvođenja
operacija.
Svakom operatoru se određuje nivo između 1 i 1200, pri
čemu se operatori višeg nivoa izvršavaju prije. Na primjer,
direktiva dynamic / 1 je u SWI-Prologu zadana kao
predefinirani operator prioriteta 1150.
PREDEFINIRANI PREDIKAT op / 3
Operatori se u Prologu definiraju
predefiniranim predikatom op / 3. Značenje
argumenata ovog predikata je sljedeće:
1. argument - nivo operatora
2. argument - položaj operanada Objašnjenje drugog argumenta:
3. argument - naziv (oznaka) operatora ◦ slovo f predstavlja operator
◦ slova x i y predstavljaju operande
Prvi argument će biti broj između 1 i 1200 Razlika između x i y je u asocijativnosti
operatora:
Drugi argument može biti jedan od sljedećih ◦ xfx - neasocijativan operator (ne
terma: mogu se dva vezati u jednom izrazu)
fx,fy,xf,yf,xfx,xfy,yfx ◦ xfy - izvođenje operatora slijeva na
desno
Treći argument može biti term ili lista terma ◦ yfx - izvođenje operatora zdesna na
lijevo
koji predstavljaju nazive terma na koje se
odnose prva dva argumenta
OPERATORI
1200 xfx -->, :-
1200 fx :-, ?-
dynamic, discontiguous, initialization, meta_predicate, module_transparent, multifile, public,
1150 fx
thread_local, thread_initialization, volatile
1100 xfy ;, |
1050 xfy ->, *->
1000 xfy ,
990 xfx :=
900 fy \+
700 xfx <, =, =.., =@=, \=@=, =:=, =<, ==, =\=, >, >=, @<, @=<, @>, @>=, \=, \==, as, is, >:<, :<
600 xfy :
500 yfx +, -, /\, \/, xor
500 fx ?
400 yfx *, /, //, div, rdiv, <<, >>, mod, rem
200 xfx **
200 xfy ^
200 fy +, -, \
100 yfx .
1 fx $
OPERATORI
Iskoristit ćemo operatore da bismo omogućili ljepše sučelje
za avanturu u što prirodnijem jeziku.
Sve dosad opisane predikate u bazi ćemo pretvoriti u
operatore i time omogućiti izdavanje komandi igraču bez
zagrada i zareza.
OPERATORI
Za odgovarajuće predikate definiramo unarne operatore na
sljedeći način:
:- op(30,fx,mjesto).
:- op(30,fx,pogledaj). % mijenjamo gledaj/1 u pogledaj/1
:- op(30,fx,idiU).
:- op(30,fx,uzmi).
:- op(30,fx,ispusti).
:- op(30,fx,jedi).
:- op(30,fx,upali).
:- op(30,fx,ugasi).
OPERATORI
Primjeri upita:

?- mjesto hodnik1. ?- pogledaj stol.


true. stol sadrzi
crvena jabuka
?- mjesto tavan. mutni napitak1
false. prozirni napitak2
true.

?- pogledaj krevet.
false.
OPERATORI
Imamo i jedan neasocijativni Primjer upita:
binarni operator za predikat
jeU / 2: ?- jabuka jeU soba1.
false.
:- op(30,xfx,jeU). ?- jabuka jeU soba2.
true.
REZ
Do sada smo radili s Prologom i vidjeli kako funkcionira
backtracking. Ponekad je dobro isključiti backtracking.
Za tu svrhu koristimo rez (cut) koji je u Prologu predstavljen s !

Da bismo prikazali kako funkcionira rez, Postavimo sljedeći upit:


definirat ćemo jednostavnu bazu i pravila:
?- pr1(X),write(X),nl,fail.
a(1). 1
a(2). 2
a(3). 3
pr1(X) :- a(X). zadnja klauzula
pr1('zadnja klauzula'). false.
PRIMJER BEZ REZA
pr1(X)

write(X)

nl

fail
PRIMJER BEZ REZA
pr1(X) a(X)

write(X)

nl

fail
PRIMJER BEZ REZA
true a(1)
pr1(X) a(X)
X=1
write(X)

nl

fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=1
write(X)

nl

fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=1 X=1
write(X)

nl

fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=1
write(X) 1
X=1
nl Ispis:
1

fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=1
write(X)

nl nl Ispis:
1
X=1
fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=1
write(X)

nl Ispis:
1
false
fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=1
write(X)
false
nl Ispis:
1

fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
false X=1
write(X)

nl Ispis:
1

fail
PRIMJER BEZ REZA
pr1(X) a(X)

write(X)

nl Ispis:
1

fail
PRIMJER BEZ REZA
true a(2)
pr1(X) a(X)
X=2
write(X)

nl Ispis:
1

fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=2
write(X)

nl Ispis:
1

fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=2 X=2
write(X)

nl Ispis:
1

fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=2
write(X) 2
X=2
nl Ispis:
1
2
fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=2
write(X)

nl nl Ispis:
1
X=2 2
fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=2
write(X)

nl Ispis:
1
false 2
fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=2
write(X)
false
nl Ispis:
1
2
fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
false X=2
write(X)

nl Ispis:
1
2
fail
PRIMJER BEZ REZA
pr1(X) a(X)

write(X)

nl Ispis:
1
2
fail
PRIMJER BEZ REZA
true a(3)
pr1(X) a(X)
X=3
write(X)

nl Ispis:
1
2
fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=3
write(X)

nl Ispis:
1
2
fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=3 X=3
write(X)

nl Ispis:
1
2
fail
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=3
write(X) 3
X=3
nl Ispis:
1
2
fail 3
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=3
write(X)

nl nl Ispis:
1
X=3 2
fail 3
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=3
write(X)

nl Ispis:
1
false 2
fail 3
PRIMJER BEZ REZA
true
pr1(X) a(X)
X=3
write(X)
false
nl Ispis:
1
2
fail 3
PRIMJER BEZ REZA
true
pr1(X) a(X)
false X=3
write(X)

nl Ispis:
1
2
fail 3
PRIMJER BEZ REZA
pr1(X) a(X)

write(X)

nl Ispis:
1
2
fail 3
PRIMJER BEZ REZA
false false
pr1(X) a(X)

write(X)

nl Ispis:
1
2
fail 3
PRIMJER BEZ REZA
false
pr1(X) a(X)

write(X)

nl Ispis:
1
2
fail 3
PRIMJER BEZ REZA
pr1('zadnja klauzula')
pr1(X)

write(X)

nl Ispis:
1
2
fail 3
PRIMJER BEZ REZA
pr1(X)
X= 'zadnja klauzula'
write(X)

nl Ispis:
1
2
fail 3
PRIMJER BEZ REZA
pr1(X)

write(X) zadnja klauzula


X= 'zadnja klauzula'
nl Ispis:
1
2
fail 3
zadnja klauzula
PRIMJER BEZ REZA
pr1(X)

write(X)

nl nl Ispis:
1
X= 'zadnja klauzula' 2
fail 3
zadnja klauzula
PRIMJER BEZ REZA
pr1(X)

write(X)

nl Ispis:
1
false 2
fail 3
zadnja klauzula
PRIMJER BEZ REZA
pr1(X)

write(X)
false
nl Ispis:
1
2
fail 3
zadnja klauzula
PRIMJER BEZ REZA
pr1(X)
false
write(X)

nl Ispis:
1
2
fail 3
zadnja klauzula
PRIMJER BEZ REZA
false
pr1(X)

write(X)

nl Ispis:
1
2
fail 3
zadnja klauzula
false.
PRIMJER – REZ1
Sljedeći primjer je: Postavimo sljedeći upit:

pr2(X) :- a(X),!. ?- pr2(X),write(X),nl,fail.


pr2('zadnja klauzula'). 1
false.
PRIMJER – REZ1
pr2(X)

write(X)

nl

fail
PRIMJER – REZ1
pr2(X) a(X)

write(X) !

nl

fail
PRIMJER – REZ1
a(1)
pr2(X) a(X)
X=1
write(X) !

nl

fail
PRIMJER – REZ1
pr2(X)
true
write(X) !
X=1
nl

fail
PRIMJER – REZ1
pr2(X)
true

write(X) !
X=1
nl

fail
PRIMJER – REZ1
pr2(X)
X=1 true

write(X) !
X=1
nl

fail
PRIMJER – REZ1
pr2(X)
true

write(X) 1 !
X=1 X=1
nl
Ispis:
1
fail
PRIMJER – REZ1
pr2(X)
true
write(X) !
X=1
nl nl
Ispis:
X=1 1
fail
PRIMJER – REZ1
pr2(X)
true

write(X) !
X=1
nl
Ispis:
false 1
fail
PRIMJER – REZ1
pr2(X)
true
write(X) !
false X=1
nl
Ispis:
1
fail
PRIMJER – REZ1
pr2(X)
false true

write(X) !
X=1
nl
Ispis:
1
fail
PRIMJER – REZ1
pr2(X)

write(X) !

nl
Ispis:
1
fail
PRIMJER – REZ1
pr2(X)
false
write(X) !

nl
Ispis:
1
fail
PRIMJER – REZ1
false
pr2(X)

write(X)

nl
Ispis:
1
fail false.
PRIMJER – REZ2
Sljedeći primjer je: Postavimo sljedeći upit:

pr3(X,Y) :- a(X),!,a(Y). ?- pr3(X,Y),write(X–Y), nl,fail.


pr3(zadnja, klauzula). 1-1
1-2
1-3
false.
PRIMJER – REZ2
pr3(X,Y)

write(X-Y)

nl

fail
PRIMJER – REZ2
pr3(X,Y) a(X)

write(X-Y) !

nl a(Y)

fail
PRIMJER – REZ2
a(1)
pr3(X,Y) a(X)
X=1
write(X-Y) !

nl a(Y)

fail
PRIMJER – REZ2
pr3(X,Y)

write(X-Y) !
X=1
nl a(Y)

fail
PRIMJER – REZ2
pr3(X,Y)

write(X-Y) !
a(1)
nl a(Y)
X=1
Y=1
fail
PRIMJER – REZ2
pr3(X,Y)

write(X-Y) !
true
nl a(Y)
X=1
Y=1
fail
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) !

nl a(Y)
X=1
Y=1
fail
PRIMJER – REZ2
pr3(X,Y)
X=1
true
Y=1
write(X-Y) !

nl a(Y)
X=1
Y=1
fail
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) 1-1 !
X=1
Y=1
nl a(Y)
X=1 Ispis:
Y=1 1-1
fail
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) !

nl nl a(Y)
X=1
X=1 Ispis:
Y=1
Y=1 1-1
fail
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) !

nl a(Y)
false X=1 Ispis:
Y=1 1-1
fail
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) !
false
nl a(Y)
X=1 Ispis:
Y=1 1-1
fail
PRIMJER – REZ2
pr3(X,Y)
false true
write(X-Y) !

nl a(Y)
X=1 Ispis:
Y=1 1-1
fail
PRIMJER – REZ2
pr3(X,Y)

write(X-Y) !

nl a(Y)

Ispis:
fail 1-1
PRIMJER – REZ2
pr3(X,Y)

write(X-Y) !

nl a(Y)

Ispis:
fail 1-1
PRIMJER – REZ2
pr3(X,Y)

write(X-Y) !
a(2)
nl a(Y)
Y=2 Ispis:
fail 1-1
PRIMJER – REZ2
pr3(X,Y)

write(X-Y) !
true
nl a(Y)
Y=2 Ispis:
fail 1-1
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) !

nl a(Y)
Y=2 Ispis:
fail 1-1
PRIMJER – REZ2
pr3(X,Y)
X=1
true
Y=2
write(X-Y) !

nl a(Y)
Y=2 Ispis:
fail 1-1
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) 1-2 !
X=1
Y=2
nl a(Y)
Y=2 Ispis:
fail 1-1
1-2
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) !

nl nl a(Y)
X=1
Y=2 Ispis:
Y=2
fail 1-1
1-2
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) !

nl a(Y)
false Y=2 Ispis:
fail 1-1
1-2
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) !
false
nl a(Y)
Y=2 Ispis:
fail 1-1
1-2
PRIMJER – REZ2
pr3(X,Y)
false true
write(X-Y) !

nl a(Y)
Y=2 Ispis:
fail 1-1
1-2
PRIMJER – REZ2
pr3(X,Y)

write(X-Y) !

nl a(Y)

Ispis:
fail 1-1
1-2
PRIMJER – REZ2
pr3(X,Y)

write(X-Y) !

nl a(Y)

Ispis:
fail 1-1
1-2
PRIMJER – REZ2
pr3(X,Y)

write(X-Y) !
a(3)
nl a(Y)
Y=3 Ispis:
fail 1-1
1-2
PRIMJER – REZ2
pr3(X,Y)

write(X-Y) !
true
nl a(Y)
Y=3 Ispis:
fail 1-1
1-2
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) !

nl a(Y)
Y=3 Ispis:
fail 1-1
1-2
PRIMJER – REZ2
pr3(X,Y)
X=1
true
Y=3
write(X-Y) !

nl a(Y)
Y=3 Ispis:
fail 1-1
1-2
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) 1-3 !
X=1
Y=3
nl a(Y)
Y=3 Ispis:
fail 1-1
1-2
1-3
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) !

nl nl a(Y)
X=1
Y=3 Ispis:
Y=3
fail 1-1
1-2
1-3
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) !

nl a(Y)
false Y=3 Ispis:
fail 1-1
1-2
1-3
PRIMJER – REZ2
pr3(X,Y)
true
write(X-Y) !
false
nl a(Y)
Y=3 Ispis:
fail 1-1
1-2
1-3
PRIMJER – REZ2
pr3(X,Y)
false true
write(X-Y) !

nl a(Y)
Y=3 Ispis:
fail 1-1
1-2
1-3
PRIMJER – REZ2
pr3(X,Y)

write(X-Y) !

nl a(Y)

Ispis:
fail 1-1
1-2
1-3
PRIMJER – REZ2
pr3(X,Y)

write(X-Y) !

nl a(Y)

Ispis:
fail 1-1
1-2
1-3
PRIMJER – REZ2
pr3(X,Y)

write(X-Y) !
false false
nl a(Y)

Ispis:
fail 1-1
1-2
1-3
PRIMJER – REZ2
pr3(X,Y)
false
write(X-Y) !

nl a(Y)

Ispis:
fail 1-1
1-2
1-3
PRIMJER – REZ2
false
pr3(X,Y)

write(X-Y)

nl

Ispis:
fail 1-1
1-2
1-3
false.
PREDIKAT problem / 1
U našu avanturu ćemo dodati neke probleme koji će
igračima “zagorčavati život”.
Probleme ćemo opisati predikatom problem / 1
Predikat mora imati sljedeća svojstva:
◦ ako je problem uspješno riješen, mora uspjeti
◦ ako problem nije riješen, mora javiti poruku i ne smije
uspjeti
◦ ako problem nije definiran, mora uspjeti
PREDIKAT problem / 1
Prvi problem će biti u tome što igraču zabranjujemo ulaz u
podrum sve dok nema fenjer i dok on nije upaljen
Definirat ćemo predikat:

problem(idiU(podrum)) :-
ima(fenjer),
upaljeno(fenjer),!.
problem(idiU(podrum)) :-
write('U podrumu je mrak!'),nl,!,fail.
PREDIKAT problem / 1
Drugi problem će biti u tome što igraču zabranjujemo izlaz
u šumu sve dok nema ključ
Definirat ćemo predikat:

problem(idiU(šuma)) :-
ima(ključ),!.
problem(idiU(šuma)) :-
write('Vrata su zaključana!'),nl,!,fail.
problem(_). % Piše se samo nakon zadnjeg problema!
PREDIKAT problem / 1
Još trebamo predefinirati predikat idiU / 1 kao:

idiU(Mjesto) :- problem(idiU(Mjesto)),
mozeIci(Mjesto),
pokret(Mjesto),
gledaj.
REZ - NAPOMENA
Treba upozoriti da u slučaju uvođenja reza u program
gubimo jednu značajku logičkog programiranja - nebitnost
redoslijeda klauzula.
Naime, ako se pojavi rez, on će spriječiti daljnje
pretraživanje baze za klauzulama koje zadovoljavaju cilj, jer
će odrezati osnovni cilj i ostaviti samo cilj iza reza.
Rez se može i izbjeći korištenjem predefiniranog predikata
not / 1, čime se dobiva logička čistoća koda i nezavisnost
poretka klauzula.
Definirajmo naš predikat problem / 1 bez upotrebe reza. Za
svaku klauzulu ćemo definirati sve uvjete.
PREDIKAT problem / 1 bez reza
problem(idiU(podrum)) :-
ima(fenjer),
upaljeno(fenjer).
problem(idiU(podrum)) :-
not(ima(fenjer)),
write('Nemaš fenjer, a u podrumu je
mrak!'),nl,fail.
problem(idiU(podrum)) :-
ima(fenjer), not(upaljeno(fenjer)),
write('Upali fenjer, u podrumu je
mrak!'),nl,fail.
PREDIKAT problem / 1 bez reza
problem(idiU(šuma)) :-
ima(ključ).
problem(idiU(šuma)) :-
not(ima(ključ)),
write('Nemaš ključ, a vrata su zaključana!'),
nl,fail.
problem(X) :- not(X = idiU(podrum)), not(X = idiU(šuma)).
PREDIKAT pritisni / 0
Definiramo uvjete za otkrivanje vrata u sobu 3:
pritisni :- polozaj(podrum),
jeU(izbočina,podrum),
not(vrata(hodnik1,soba3)),
assertz(vrata(hodnik1,soba3)),
write('Izbočina se miče! Tajna vrata su otvorena!').
pritisni :- polozaj(podrum),
jeU(izbočina,podrum),
vrata(hodnik1,soba3),
write(‘Ne mogu!'), nl, fail.
PREDIKAT pritisni / 0

pritisni :- not(polozaj(podrum)),
write('Nisi u podrumu!'), nl, fail.
pritisni :- polozaj(podrum),
not(jeU(izbočina,podrum)),
write('Što da pritisnem?'), nl, fail.
PREDIKAT uzeti / 1 - predefiniranje
Predefinirat ćemo predikat uzeti /1 tako da se, ako
uzimamo blago, u sobi3 pojavi ključ koji se nalazio ispod
blaga:
uzeti(Stvar) :- Stvar \= 'blago',
retract(lokacija(Stvar, _)),
asserta(ima(Stvar)),
write('Uzeo sam!'), nl.
uzeti(Stvar) :- Stvar = 'blago',
retract(lokacija(Stvar, _)),
asserta(ima(Stvar)),
assertz(lokacija(ključ,soba3)),
assertz(opisStvari(ključ, opis(srebrni, 100))),
write('Uzeo sam! A tu je i ključ!'), nl.
Govorili smo o…

You might also like