Vstup a výstup Vestavěné predikáty (pokračování) Vstupní a výstupní proudy: vestavěné predikáty ■ změna (otevření) aktivního vstupního/výstupního proudu: see(S)/tell (S) ctěni( Soubor ) :- see( Soubor ), cteni_ze_souboru( Informace ), see( user ). ■ uzavření aktivního vstupního/výstupního proudu: seen/told ■ zjištění aktivního vstupního/výstupního proudu: seeing(S)/te"l"ling(S) ctěni( Soubor ) :- seeing( StarySoubor ), see( Soubor ), cteni_ze_souboru( Informace ), seen, see( StarySoubor ). Hana Rudová, Logické programování I, 21. března 2012 uživatelsky terminal program může číst data ze vstupního proudu (input stream) program může zapisovat data do výstupního proudu (output stream) dva aktivní proudy ■ aktivní vstupní proud ■ aktivní výstupní proud uživatelský terminál - user ■ datový vstup z terminálu chápán jako jeden ze vstupních proudů ■ datový výstup na terminál chápán jako jeden z výstupních proudů user user soubor 1 soubor 2 —ta program —ta vstupni proudy vystupni proudy Hana Rudová, Logické programování I, 21. března 201 2 Sekvenční přístup k textovým souborům čtení dalšího termu: read(Term) ■ při čtení jsou termy odděleny tečkou | ?- read(A), read( ahoj(B) ), read( [C,D] ). |: ahoj. ahoj C petre ). [ ahojC 'Petre!' ), jdeme ]. A = ahoj, B = petre, C = ahoj('Petre!'), D = jdeme ■ po dosažení konce souboru je vrácen atom end_of_f i le zápis dalšího termu: write(Term) ?- writeC ahoj ). ?- writeC 'Ahoj Petre!' ). nový řádek na výstup: nl N mezer na výstup: tab(N) čtení/zápis dalšího znaku: getO(Znak) , get(NeprazdnyZnak)/put(Znak) ■ po dosažení konce souboru je vrácena -1 Hana Rudová, Logické programování 1,21. března 201 2 Príklad čtení ze souboru process_file( Soubor ) :- seeing( StarySoubor ), see( Soubor ), repeat, read( Term ), process_term( Term ), Term == end_of_file, i ■ i seen, see( StarySoubor ). repeat. repeat :- repeat. % zjištění aktivního proudu % otevření souboru Soubor % čtení termu Term % manipulace s termem % je konec souboru? % uzavření souboru % aktivace původního proudu % opakování Hana Rudová, Logické programování I, 21. března 2012 5 Všechna řešení ■ Backtracking vrací pouze jedno řešení po druhém ■ Všechna řešení dostupná najednou: bagof/3 , setof/3, findall/3 ■ bagof( X, P, S ): vrátí seznam S, všech objektů X takových, že P je splněno vek( petr, 7 ) . vek( anna, 5 ). vek( tomas, 5 ). ?- bagofC Dite, vek( Dite, 5 ), Seznam ). Seznam = [ anna, tomas ] ■ Volné proměnné v cíli P jsou všeobecně kvantifikovány ?- bagofC Dite, vek( Dite, Vek ), Seznam ). Vek = 7, Seznam = [ petr ]; Vek = 5, Seznam = [ anna, tomas ] Čtení programu ze souboru ■ Interpretování kódu programu ■ ?- consult(program). ■ ?- consultCprogram.pl') . ■ ?- consult( [programl, 'program2.pl'] ). ■ Kompilace kódu programu ■ ?- compile( [programl, 'program2.pl']). ■ ?- [program]. ■ ?- [user]. zadávání kódu ze vstupu ukončené CTRL+D ■ další varianty podobně jako u interpretování ■ typické zrychlení: 5 až 10 krát Hana Rudová, Logické programování 1,21. března 201 2 6 Všechna řešení II. ■ Pokud neexistuje řešení bagof(X, P, S) neuspěje ■ bagof: pokud nějaké řešení existuje několikrát, pak S obsahuje duplicity ■ bagof, setof, findall: P je libovolný cíl vek( petr, 7 ). vek( anna, 5 ). vek( tomas, 5 ). ?- bagofC Dite, ( vek( Dite, 5 ), Dite \= anna ), Seznam ). Seznam = [ tomas ] ■ bagof, setof, findall: na objekty shromažďované vX nejsou žádná omezení: Xje term ?- bagofC Dite-Vek, vek( Dite, Vek ), Seznam ). Seznam = [petr-7,anna-5,tomas-5] Hana Rudová, Logické programování I, 21. března 2012 7 Hana Rudová, Logické programování 1,21. března 201 2 Existenční kvantifikátor „" " ■ Přidání existenčního kvantifikátoru ,," " => hodnota proměnné nemá význam ?- bagofC Dite, Vek"vek( Dite, Vek ), Seznam ). Seznam = [petr.anna.tomas] ■ Anonymní proměnné jsou všeobecně kvantifikovány, i když jejich hodnota není (jako vždy) vracena na výstup ?- bagofC Dite, vek( Dite, _Vek ), Seznam ). Seznam = [petr] ; Seznam = [anna.tomas] ■ Před operátorem ,," " může být i seznam ?- bagofC Vek ,[]meno,Přijmeni]"vek( ]meno, Prijmeni, Vek ), Seznam ). Seznam = [7,5,5] Hana Rudová, Logické programování I, 21. března 2012 9 Všechna řešení III. ■ setof( X, P, S ): rozdíly od bagof ■ S je uspořádaný podle @< ■ případné duplicity v S jsou eliminovány ■ findalK X, P, S ): rozdíly od bagof ■ všechny proměnné jsou existenčně kvantifikovány ?- findalK Dite, vek( Dite, Vek ), Seznam ). svS jsou shromažďovány všechny možnosti i pro různá řešení => findall uspěje přesně jednou ■ výsledný seznam může být prázdný => pokud neexistuje řešení, uspěje a vrátí S = [] ■ ?- bagofC Dite, vek( Dite, Vek ), Seznam ). Vek = 7, Seznam = [ petr ]; Vek = 5, Seznam = [ anna, tomas ] ?- findalK Dite, vek( Dite, Vek ), Seznam ). Seznam = [petr.anna.tomas] Hana Rudová, Logické programování 1,21. března 201 2 1 0 Testování typu termu Určení počtu výskytů prvku v seznamu var(X) nonvar(X) atom(X) i nteger(X) float (X) atomi c(X) compound(X) X je volná proměnná X není proměnná X je atom (pavel, 'Pavel Novák', <-->) X je integer X je float X je atom nebo číslo X je struktura count( X, S, N ) :- count( X, S, 0, N ). count( _, [], N, N ). count( X, [X|S], NO, N) :- !, Nl is NO + 1, count( X, S, Nl, N). count( X, [_|S], NO, N) :- count( X, S, NO, N). :-? count( a, [a,b,a,a], N ) N=3 :-? count( a, [a,b,X,Y], N). N=3 count( _, [], N, N ). count( X, [Y|S], NO, N ) :- nonvar(Y), X = Y, !, Nl is NO + 1, count( X, S, Nl, N ). count( X, [_|S], NO, N ) :- count( X, S, NO, N ). Hana Rudová, Logické programování 1,21. března 2012 11 Vestavěné predikáty Hana Rudová, Logické programování 1,21. března 2012 12 Vestavěné predikáty Konstrukce a dekompozice atomu Konstrukce a dekompozice termu Atom (opakování) ■ řetězce písmen, čísel, „_" začínající malým písmenem: pavel , pavel_novak, x2, x4_34 ■ řetězce speciálních znaků:+, <->, ===> ■ řetězce v apostrofech: ' Pavel ' , 'Pavel Novák', 'prší', 'ano' ?- 'ano'=A. A = ano Řetězec znaků v uvozovkách ■ př. "ano", "Pavel" ?- A="Pavel". ?- A="ano". A = [80,97,118,101,108] A=[97,110,111] ■ př. použití: konstrukce a dekompozice atomu na znaky, vstup a výstup do souboru Konstrukce atomu ze znaků, rozložení atomu na znaky name( Atom, SeznamASCIIKodu ) nameC ano, [97,110,111] ) nameC ano, "ano" ) Hana Rudová, Logické programování I, 21. března 2012 13 Vestavěné predikáty ■ Konstrukce a dekompozice termu Term =.. [ Funktor | SeznamArgumentu ] a(9,e) =.. [a,9,e] Cil =.. [ Funktor | SeznamArgumentu ], call( Cil ) atom =. . X => X = [atom] ■ Pokud chci znát pouze funktor nebo některé argumenty, pak je efektivnější: functor( Term, Funktor, Arita ) functorC a(9,e), a, 2 ) functor(atom,atom,0) functor(l,1,0) arg( N, Term, Argument ) argC 2, a(9,e), e) Hana Rudová, Logické programování 1,21. března 2012 14 Vestavěné predikáty Rekurzivní rozklad termu Term je proměnná (var/l), atom nebo číslo (atomic/1) => konec rozkladu Term je seznam ([_!_])=> []... řešen výše jako atomic procházení seznamu a rozklad každého prvku seznamu Term je složený (=../2 , functor/3) => procházení seznamu argumentů a rozklad každého argumentu Příklad: ground/1 uspěje, pokud v termu nejsou proměnné; jinak neuspěje ground(Term) :- atomic(Term), !. ground(Term) :- var(Term), !, fail. groundC[H|T]) :- !, ground(H), ground(T). ground(Term) :- Term =.. [ _Funktor | Argumenty ], groundC Argumenty ). ?- ground(s(2,[a(l,3),b,c],X)). ?- ground(s(2, [a(l,3),b,c])). no yes Hana Rudová, Logické programování I,21.března2012 15 Vestavěné predikáty Příklad: dekompozice termu I. ■ count_term( Integer, Term, N ) určí počet výskytů celého čísla v termu ■ ?- count_term( 1, a(l,2,b(x,z(a,b,1)),Y), N ). N=2 ■ count_term( X, T, N ) :- count_term( X, T, 0, N). count_term( X, T, NO, N ) :- integer(T), X = T, !, N is NO + 1. count_term( _, T, N, N ) :- atomic(T), !. count_term( _, T, N, N ) :- var(T), !. count_term( X, T, NO, N ) :- T =.. [ _ | Argumenty ], count_arg( X, Argumenty, NO, N ). count_arg( _, [], N, N ). count_arg( X, [ H | T ], NO, N ) :- count_term( X, H, 0, NI), N2 is NO + NI, count_arg( X, T, N2, N ). ■ ?- count_term( 1, [a,2,[b,c],[d,[e,f],Y]], N ). count_term( X, T, NO, N ) :- T = [_|_], !, count_arg( X, T, NO, N ). klauzuli přidáme před poslední klauzuli count_term/4 Hana Rudová, Logické programování 1,21. března 2012 16 Vestavěné predikáty Cvičení: dekompozice termu ■ Napište predikát substitute( Podterm, Term, Podterml, Terml), který nahradí všechny výskyty Podterm v Term termem Podterml a výsledek vrátí v Terml ■ Předpokládejte, že Term a Podterm jsou termy bez proměnných ■ ?- substitute( sin(x), 2*sin(x)*f(sin(x)), t, F ). F=2*t*f(t) Hana Rudová, Logické programování 1,21. března 201 2 17 Vestavěné predikáty