Ladění, pred. vyšších řádů (7) Jan Hric, KTI MFF UK, a
Ladění Krabičkový model 4 brány: Call: první zavolání cíle Exit: úspěšné ukončení cíle Redo: návrat do cíle, hledání alternativ Fail: celkový neúspěch vstupní brány: Call, Redo výstupní: Exit, Fail
Ladění II - predikáty trasování (taky v menu): trace/0 zapne notrace/0 vypne spypointy: spy(P/N) nastaví spypoint nospy(P/N) zruší -”- ladění pomocí spypointů (i v menu) debug/0 zapne ladění nodebug/0 vy pne ladění debugging/0 vy píše nastavení
Práce s množinami řešení převod reprezentací: backtracking na seznam řešení setof(Term, Cil, Seznam) Pro každou nalezenou substituci S, která splňuje Cil, se d.s. S( Term ) přidá do Seznam u najde všechny hodnoty Term u (s aplikovanou subs. S), které splňují Cil vráti jejich Seznam, uspořádaný, bez duplicit Seznam je vždy neprázdný, při prázdném výsl. seznamu setof/3 neuspěje backtrackuje přes volné proměnné v Cíli Cíl tvaru V1^V2^...^C (pouze zde: setof, bagof) V1,V2,... jsou existenčne kvantifikované, na jejich hodnotách nezáleží, nebacktrackuje sa přes ně Cíl může být složený (v závorkách) bagof/3 analogicky, vrací neuspořádanou multimnožinu řešení (bag) findall/3 Všechny proměnné jsou existenčně kvantifikované, uspěje jednou
setof – příklady chování ?- setof(R, D^rodic(R,D), L).% existenční proměnná D L=[adam,anna,bohus,bozena] ; no ?- setof(R, rodic(R,D), L).% backtracking pro různé hodn. D L=[adam,anna] ;%{D=bohus} L=[adam,anna] ;%{D=bara} L=[bohus,bozena] ; %{D=cyril} no ?- setof(M+O, D^(rodic(M,D),rodic(O,D),M\=O),L).% struktura L=[adam+anna,anna+adam,bohus+bozena,bozena+bohus] ; no ?- bagof(R, D^rodic(R,D), L).% bag L=[adam,anna,adam,anna,bohus,bozena] ; no rodic(anna,bohus).% jeden fakt procedury rodic/2 rodic(adam,bohus).% význam: Adam je rodicem Bohuse rodic(anna,bara). rodic(adam,bara). rodic(bohus,cyril). rodic(bozena,cyril).
Příklad - setof reprezentace grafů: graf([V-OV],[h(V1,V2,OH)] interface: vrchol/3, hrana/4 vrchol(graf(Vs,_Hs),V,OV) :-member(V-OV,Vs). hrana(graf(_Vs,Hs),V1,V2,OH):-member(h(V1,V2,OH),Hs). druhá reprezentace: [V1-OV-[V2-OH]] prevod(G1,G2):- setof(V1-OV-Vs, (vrchol(G1,V1,OV),setof(V2-OH,hrana(G1,V1,V2,OH),Vs)), G2). DC: dopracujte, aby G2 obsahoval i izolované vrcholy Použití existenčne kvantifikovaných proměnných: sousede(G1,V,S):-setof(V2,OV^hrana(G1,V,V2,OV),S). Pro setof(V2,hrana(G1,V,V2,_),S) backtrackuje přes různé hodnoty ohodnocení a teda vrací nevhodné výsledky
Metoda “generuj a testuj” použití: prohledávací úlohy, využijeme prologovské prohledávání (do hloubky) př.: obarvení grafu n barvami, tvorba krížovky, kombinatorické problémy... posbírat rozumná řešení pomocí setof musí být “málo řešení” NP-úplné problémy lehko popíšete, ale … batoh(Bs,S,Os):- % najít podmnožinu Bs, že její součet je S subset(Os,Bs), suma(Os,S). problém: obvykle neefektivní postup generovat po částech a hned testovat, co se dá
Převod termu na cíl: call/1 call/1 převede term v argumentu na cíl a zavolá ho akceptuje i složené cíle jméno volaného predikátu musí být známé proměnné na místě predikátů: převod: X --> call(X) cíl lze zkonstrovat za běhu (ze známých pred.) => „late binding“, „hooks“ př.: not, \+, setof, … not(X):-call(X),!,fail;true. př.: sekvence(P,Q):- call(P),call(Q). př.: sekvence2(P,Q):- call((P,Q)). argumenty se přidají pomocí =.. problémy s přejmenováním proměnných => používat jen na termy bez proměnných (zatím) Mimo standard: call/n, přidá další argumenty a zavolá Př.: call(append([X]),I,O), jako append([X],I,O) Nepřejmenuje proměnné ve volaném cíli -> ručně: copy_term(Term,T0)
Programování vyšších řádů predikáty (jména p.) jako vstupní parametry, (tj. pointry na p.) znovupoužitelnost kódu, vyšší abstrakce parametrické spracování seznamu: map(Pred, In, Out) Pred/2 se zavolá na každý prvek In a vrátí prvek Out př.: první, poslední sloupec matice map(_P,[],[]). map( P,[I|Is],[O|Os]):- mycall(P,[I,O]),map(P,Is,Os). % nebo: call(P,I,O) posledni_sloupec(M,S):-map(last,M,S). last(L,Last):-append(_,[Last],L). argumenty se přidají pomocí =..,anebo použít call/n, n>1 (SWI) mycall(P,Args):- C=..[P|Args], call(C). P je 1 jméno predikátu (ne složený cíl), Volané cíle jsou pojmenované predikáty v db. idea map je použitelná na libovolnou d.s., na víc args. Procedurální parametry: už jsme použili: foreach DC: akumuluj/3, prvky seznamu jsou data, ale i „příkazy“
(Částečná spec. argumentů) predikát má několik prvních arg. daných, zbylé jsou parametry map_matice(P,I,O):- map(map(P),I,O). % matice jako seznam seznamu map2_matice(P,I1,I2,O):-map2(map2(P),I1,I2,O). plus_matice(M1,M2,M):-map2_matice(plus,M1,M2,M). plus(X1,X2,X3):- X3 is X1 + X2. map2(_P,[],[],[]). map2( P,[I|Is],[J|Js],[O|Os]):- mycall2(P,[I,J,O]),map2(P,Is,Js,Os). % nebo: call(P,I,.J,O) nasobmat(C,M1,M0):-map(map(mult( C)),M1,M0). %násobení matice konstantou mult(C,X1,X0):- X0 is C * X1. musíme změnit/zobecnit mycall mycall2(P,Args):- % P je jméno jednoho již definovaného predikátu, srv. FP: anonymní fce P=.. [Pred|Args0], % args bez volných proměnných append(Args0,Args,Args1), C=..[Pred|Args1], call(C). předávané predikátové argumenty by měli být bez volných proměnných volné proměnné jsou sdílené mezi všemi voláními, neproběhne přejmenování proměnných => často nežádoucí chování, náchylné k chybám
(Parametrické zpracování seznamu) funkční symbol je relace mezi složkami a celou strukturou f.s. nahradíme jinou relací - předanou parametrem zpracuj(Snil,_Scons,[],Snil). zpracuj(Snil, Scons,[I|Is],O):- zpracuj(Snil,Scons,Is,O1), mycall(Scons,[I,O1,O]). suma(I,O):-zpracuj(0,plus,I,O). length(I,O):-zpracuj(0,plus1,I,O). mappend(I,O):-zpracuj([],append,I,O). plus(X,Y,Z):-Z is X+Y. plus1(_X,Y,Z):-Z is Y+1.
(Parametrické zpracování seznamu II) idea zpracuj: (anglicky fold) zpracuj(E, , [X1,.., Xn], Out) Out := X1 (X2 (... (Xn E)..)) relace: (Xn,E,A1), (Xn-1,A1,A2),.. (X1,An- 1,An),An=Out jiná relace: R(X1,E,A1), R(X2,A1,A2),.. R(Xn,An-1,An),An=Out další varianty filter(_P,[],[]). filter( P,[I|Is],O):- (mycall(P,[I]) -> O=[I|O1] ; O=O1), filter(P,Is,O1).