![]() |
![]() |
Osnova
- Cyklus řízený neúspěchem
- Modifikace interní databáze
- Množinové predikáty (All solutions)
- Zpět na stránku jen se zadáním
- Cyklus řízený neúspěchem
může mít tyto formy:a) uzivatelsky_generator_i_nekonecny ... uzivatelsky_test b) repeat, i_o_predikat ... uzivatelsky_test c) uzivatelsky_generator_konecny ... failKdyž uživatelský test neuspěje, cyklus pokračuje, když uspějě, cyklus končí. Pokud uživatelský test nikdy neuspějě a generátor je nekonečný, bude i cyklus nekonečný. Uvnitř cyklu využíváme predikáty s vedlejším efektem (napr. I/O - vstup/výstup), protože hodnoty proměnných se po neúspěchu zapomenou.
priklad_b:- repeat, read(X), zpracuj(X), X=konec. zpracuj(_).- Modifikace interní databáze, predikáty assert/1, retract/2
Tyto predikáty používáme pouze v omezené míře, protože narušují logické čtení programu, zejména bychom neměli modifikovat predikáty zevnitř (v jejich těle). Nejvhodnější použití je například přidání již odvozeného tvrzení (efektivita), uchování málo používaných "globálních" proměnných a pod.
Přidání již odvozeného tvrzení, tzv. lemma/1:
lemma(P):-call(P),asserta((P:-!)).Je nutné přidávat na začátek predikátu (asserta/1) a odvození odříznout řezem.Příklad použití lemma/1:
:-op(500,xfx,'=>'). % definice infixoveho operatoru - sipka :- dynamic hanoi1/5. % deklarace dynamickeho predikatu hanoi1/5 hanoi(N,A,B,C,R):-hanoi1(N,A1,B1,C1,R-[]),A1=A,B1=B,C1=C. hanoi1(1,A,B,C,[A=>B|R]-R). hanoi1(N,A,B,C,R0-R):-N>1, N1 is N-1, hanoi1(N1,A,C,B,R0-R1), asserta((hanoi1(N1,A,C,B,R0-R1):-!)), R1=[A=>B|R2], hanoi1(N1,C,B,A,R2-R).- dotaz
- Proč není predikát hanoi/5 definován následujícím způsobem?
hanoi(N,A,B,C,R):-hanoi1(N,A,B,C,R-[]).Takový predikát by ukládal konktrétní řešení, tj. "přesuň 3 kruhy z 1. tyče na 3. tyč pomocí 2. tyče". Toto řešení by nebylo použitelné například pro úlohu "přesuň 3 kruhy z 2. tyče na 3. tyč pomocí 1. tyče" a musela by se počítat znovu. Původní řešení pracuje s proměnnými místo názvu tyčí, takže je uložena úloha "přesuň 3 kruhy z tyče A na B pomocí C" a ta je použitelná pro oba uvedené případy.
- Množinové predikáty (All-solutions)
- Napište program, který najde seznam všech detí daného nebo libovolného otce collect(Father,Kids) s využitím nasledující databáze:
father(petr,petra). father(petr,pavla). father(pavel,jana). father(pavel,jan).Sbírání řešení dopředným cyklem (tzv. naivní řešení)
collect(X,Cs):-c(X,[],Cs). c(X,A,Cs):-father(X,C), nm(C,A), /*/ !, c(X,[C|A],Cs). c(X,Cs,Cs). nm(_,[]).%:-!. nm(H,[X|T]):-H\==X,nm(H,T).Program je velice neefektivní v některých případech nedává správné výsledky
- výsledky bez řezu /*/ (moc řešení)| ?- collect(petr,D). D = [pavla,petra] ? ; D = [petra] ? ; D = [petra,pavla] ? ; D = [pavla] ? ; D = [] ? ; no | ?- collect(O,D). D = [pavla,petra], O = petr ? ; D = [petra], O = petr ? ; D = [petra,pavla], O = petr ? ; D = [pavla], O = petr ? ; D = [jan,jana], O = pavel ? ; D = [jana], O = pavel ? ; D = [jana,jan], O = pavel ? ; D = [jan], O = pavel ? ; D = [] ? ; no- s řezem /*/ (málo řešení)| ?- collect(petr,D). D = [pavla,petra] ? ; no | ?- collect(O,D). D = [pavla,petra], O = petr ? ; noObecné sbíraní řešení v cyklu řízeném neúspěchem:fa(X,G,_):- asserta('$instance'('$mark')), call(G), asserta('$instance'(X)), fail. fa(X,_,Xs):- retract('$instance'(X)), r(X,Xs,[]),!. r(X,Xs,Ys):- X\=='$mark', retract('$instance'(X1)), !, r(X1,Xs,[X|Ys]). r('$mark',Xs,Xs).Ukázkové odpovědi predikátu fa/3 a vestavých findall/3, setof/3, bagof/3:| ?- fa(X,father(Y,X),I). I = [petra,pavla,jana,jan], X = jan ? ; no | ?- findall(X,father(Y,X),I). I = [petra,pavla,jana,jan] ? ; no | ?- fa(X,father(petr,X),I). I = [petra,pavla], X = pavla ? ; no | ?- findall(X,father(petr,X),I). I = [petra,pavla] ? ; no- seskupené podle instanciace volné proměnné Y| ?- bagof(X,father(Y,X),I). I = [jana,jan], Y = pavel ? ; I = [petra,pavla], Y = petr ? ; no- setof/3 navíc třídí a odstraňuje duplikace| ?- setof(X,father(Y,X),I). I = [jan,jana], Y = pavel ? ; I = [pavla,petra], Y = petr ? ; no- existenční kvantifikace (hodnota Y nás nenezajímá, stačí že existuje)| ?- setof(X,Y^father(Y,X),I). I = [jan,jana,pavla,petra] ? ; no- vnořování| ?- setof(F:K,setof(X,father(F,X),K),I). I = [pavel:[jan,jana],petr:[pavla,petra]] ? ; no
^