Programové struktury


Prolog - seznamy, findall, řezy, programování textovek


Program 1 - ukázka práce se seznamy

Přiřazování seznamů:

seznam([1, 2, 3]).
pikacu1 :- write([1, 2, 3, 4, 5]).
pikacu2 :- seznam(X), write(X).

Vzpomeňme na prednášku:

member(H, [H|T]).
member(X, [H|T]):-member(X, T).

A ještě jedna trpká vzpomínka:

append([], X, X).
append([H|X], Y, [H|Z]) :- append(X, Y, Z).

Vyzkoušejte si v listeneru následující dotazy:

?- append([1,2,3],[4,5,6],LIST).
?- append(L1,L2,[1,2,3,4,5]).

Upovídanější verze predikátu append (funkčně však naprosto shodná):

append2([], X, X) :- write('Zabralo prvni pravidlo'), nl.
append2([H|X], Y, [H|Z]) :- write('H je '), write(H), write('   '), write(X), write(Y), write(Z), nl, 
                            append2(X, Y, Z), write(X), write(Y), write(Z), nl.

Vyzkoušejte v listeneru následující dotaz:

?- append2([1,2,3],[4,5,6],LIST).

stáhnout


Program 2 - hledání cesty v orientovaném grafu

Definice grafu:

hrana(1, 4).
hrana(1, 5).
hrana(2, 1).
hrana(2, 4).
hrana(3, 1).
hrana(3, 2).
hrana(3, 4).
hrana(4, 5).

Rekurzivní definice, posloupnost procházených uzlů se ukládá do seznamu:

cesta(X,Y,[X,Y]) :- hrana(X,Y).
cesta(X,Y,[X|T]) :- hrana(X,Z), cesta(Z,Y,T).

Použití predikátu FINDALL (v listeneru) a výpis seznamu s X, pro které je splněn predikát cesta(2, 5, X):

?- findall(X, cesta(2, 5, X), LIST_OF_Xs).

Použití predikátu FINDALL (v programu) a výpis seznamu s X, pro které je splněn predikát cesta(2, 5, X):

fa1 :- findall(X, cesta(2, 5, X), LIST_OF_Xs), write(LIST_OF_Xs).

Jiná možnost aneb jak "udělat to samé" jinými prostředky:

fa2 :- cesta(2, 5, X), write(X), nl, fail.
fa2.

stáhnout (všiměte si mj. štábní kultury a své programy pište podle tohoto vzoru)


Program 3 - MoveWump (příklad na vysvětlení predikátu "!")

Graf - která místnost je spojena s kterou:

connected(1, 4).
connected(1, 5).
connected(2, 1).
connected(2, 4).
connected(3, 1).
connected(3, 2).
connected(3, 4).
connected(4, 5).

Kolikátý pokus o splnění cíle ... při každém neúspěchu plnění "connected" se díky "!" snažíme najít novou unifikaci proměnné X v predikátu "pokus(X)", což je podcíl cíle "go":

pokus(1).
pokus(2).
pokus(3).
pokus(4).
pokus(5).

Inicializace. Na začátku programu je Wumpus v místnosti číslo 2:

wumpus(2).

Sledujeme pokusy a pohyb Wumpuse:

go :- pokus(X), write('Pokus cislo '), write(X), 
      nl, movewumpus, nl, 
      write('Skoncil pokus cislo '), write(X).

Nejprve se X unifikuje s číslem místnosti, kde právě Wumpus je. Pak se hledá místnost Y, do které by bylo možno Wumpuse přesunout. Z databáze se vyjme fakt "wumpus(X)" a naopak se do ni přidá fakt "wumpus(Y)".

movewumpus :- wumpus(X), 
              write('Predikat "movewumpus" v akci ... '),nl,
              write('Pred testem CONNECTED je Wumpus v mistnosti '), write(X),nl,
              !,connected(X,Y),retract(wumpus(X)),
              assert(wumpus(Y)),
              write('Po testu CONNECTED je Wumpus v mistnosti '), write(Y).
movewumpus:-write('I do nothing').

Teprve tady bude vidět kouzlo operátoru "!" -> po čtvrtém příkazu "go." se neunifikuje s X v predikátu wumpus(X), ale v predikátu pokus(X) tedy "o uroveň výše". Je to vidět například z toho, že se podruhé nevypisuje hláška 'Predikat "movewumpus" v akci ... '

Pro stále tápající: Zkuste odstranit vykřičník z pravidla "movewumpus" a uvidíte.

Přidáme "wumpus(8).", aby byl vidět další pokus o unifikaci v movewumpus.

wumpus(8).

stáhnout


Program 4 - Wumpus

stáhnout (originální verze)

stáhnout (modifikovaná verze - vypisuje se, kde wumpus je)





  Zpět  

Poslední změna: 24. 2. 2004
Josef Steinberger