Čtení ze souboru Vstup/výstup, databázové operace, rozklad termu Predikáty pro vstup a výstup I ?- read(A), read( ahoj(B) ), read( [C,D] ). |: ahoj. ahoj( petre ). [ ahoj( 'Petre!' ), jdeme ]. A = ahoj, B = petre, C = ahoj('Petre!'), D = jdeme I ?- write(a(l)), write('.'), nl, write(a(2)), write('.'), nl. a(l). a(2). yes ■ seeing, see, seen, read ■ telling, tell, told, write ■ see/tell(Soubor) ■ pokud Soubor není otevřený: otevření a aktivace ■ pokud Soubor otevřený: pouze aktivace (tj. udělá z něj aktivní vstupní/výstupní stream) ■ standardní vstupní a výstupní stream: user Hana Rudová, Logické programování I, 10. dubna 2012 3 Vstup/výstup, databázové operace, rozklad termu process_file( Soubor ) :- seeing( StarySoubor ), see( Soubor ), repeat, read( Term ), process_term( Term ) , Term == end_of_file, % zjištěni aktivniho proudu % otevřeni souboru Soubor % čteni termu Term % manipulace s termem % je konec souboru? seen, see( StarySoubor ). % uzavřeni souboru % aktivace původniho proudu repeat. repeat repeat. % vestavěný predikát Hana Rudová, Logické programování 1,10. dubna 201 2 Vstup/výstup, databázové operace, rozklad termu Příklad: vstup/výstup Napište predikát uloz_do_souboru( Soubor ), který načte několik fakt ze vstupu a uloží je do souboru Soubor. I ?- uloz_do_souboru( 'soubor.pl ' ). I: faktCmi rek, 18). I: fakt(pavel,4). I: end_of_file. yes I ?- consult(soubor). % Consulting /home/hanka/soubor.pl... % consulted /home/hanka/soubor.pl in module user, 0 msec % 376 bytes yes I ?- 1 istingCfakt/2) . % pozor:listing/1 lze použít pouze při consult/1 (ne u compile/1) fakt(mi rek, 18). faktCpavel, 4). yes Hana Rudová, Logické programování 1,10. dubna 201 2 Vstup/výstup, databázové operace, rozklad termu Implementace: vstup/výstup uloz_do_souboruC Soubor ) :-seeingC StaryVstup ), tellingC StaryVystup ), see( user ), tel 1 C Soubor ), repeat, read( Term ), process_term( Term ), Term == end_of_file, i seen, told, tellC StaryVystup ), see( StaryVstup ). process_term(end_of_file) :- !. process_term( Term ) :- writeC Term ), writeC'.'), nl. Hana Rudová, Logické programování I, 10. dubna 2012 5 Vstup/výstup, databázové operace, rozklad termu Databázové operace ■ Databáze: specifikace množiny relací ■ Prologovský program: programová databáze, kde jsou relace specifikovány explicitně (fakty) i implicitně (pravidly) ■ Vestavěné predikáty pro změnu databáze během provádění programu: assert( Klauzule ) přidání Klauzule do programu asserta( Klauzule ) přidání na začátek assertz( Klauzule ) přidání na konec retract( Klauzule ) smazání klauzule unifikovatelné s Klauzule ■ Pozor: retract/1 lze použít pouze pro dynamické klauzule (přidané pomocí assert) a ne pro statické klauzule z programu ■ Pozor: nadměrné použití těchto operací snižuje srozumitelnost programu Hana Rudová, Logické programování I, 10. dubna 201 2 6 Vstup/výstup, databázové operace, rozklad termu Databázové operace: příklad Napište predikát vytvor_program/0, který načte několik klauzulí ze vstupu a uloží je do programové databáze. | ?- vytvor_program. |: faktCpavel, 4). |: pravidlo(X.Y) :- fakt(X.Y). |: end_of_file. yes | ?- 1 isting(fakt/2). faktCpavel, 4). yes | ?- listingCpravidlo/2). pravidlo(A, B) :- fakt(A, B). yes | ?- clauseC pravidloCA, B) , C) . % clause/2 použitelný pouze pro dynamické klauzule C = fakt(A,B) ? yes Hana Rudová, Logické programování I, 10. dubna 2012 7 Vstup/výstup, databázové operace, rozklad termu Databázové operace: implementace vytvo r_p rog ram :- seeingC StaryVstup ), seeC user ) , repeat, readC Term ), uloz_termC Term ), Term == end_of_file, i seen, seeC StaryVstup ). uloz_termC end_of_file ) :- !. uloz_termC Term ) :- assertC Term ). Hana Rudová, Logické programování I, 10. dubna 201 2 8 Vstup/výstup, databázové operace, rozklad termu Konstrukce a dekompozice termu 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í I, 10. dubna 2012 Vstup/výstup, databázové operace, rozklad termu Rekurzivní rozklad termu Term je proměnná (var/l), atom nebo číslo (atomic/1) => konec rozkladu Term je seznam ([_|_]) => 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), !. % Term je atom nebo čislo NEBO ground(Term) :- var(Term), !, fail. % Term neni proměnná NEBO groundC[H|T]) :- !, ground(H), ground(T). % Term je seznam a ani hlava ani těl % neobsahuji proměnné NEBO ground(Term) :- Term =.. [ _Funktor | Argumenty ], % je Term složený groundC Argumenty ). % a jeho argumenty % neobsahuji proměnné ?- ground(s(2,[a(l,3),b,c],X)). ?- ground(s(2,[a(l,3),b,c])). yes Hana Rudová, Logické programování 1,10. dubna 201 2 Vstup/výstup, databázové operace, rozklad termu subterm(S,T) Napište predikát subterm(S,T) pro termy S a T bez proměnných, které uspějí, pokud je S podtermem termu T. Tj. musí platit alespoň jedno z ■ podterm S je právě term T NEBO ■ podterm S se nachází v hlavě seznamu T NEBO ■ podterm S se nachází v těle seznamu T NEBO ■ T je složený term (compound/1) a S je podtermem některého argumentu T ■otestujte :- subterm(l,2). pokud nepoužijeme (compound/1), pak tento dotaz cyklí ■otestujte :- subterm(a, [1,2]) . ověřte, zda necyklí (nutný červený řez níže) | ?- subterm(sin(3),b(c,2,[l,b],sin(3) ,a)) . yes subterm(T.T) :- !. subtermCS,[H|_]) :- subterm(S,H) , !. subtermCS, [_|T]) :- !, subtermCS,T) . subtermCS,T) :- compoundCT), T=..[_|Argumenty], subtermCS.Argumenty). Hana Rudová, Logické programování I,10.dubna2012 11 Vstup/výstup, databázové operace, rozklad termu same(A,B) Napište predikát same(A, B), který uspěje, pokud mají termy A a B stejnou strukturu. Tj. musí platit právě jedno z ■ A i B jsou proměnné NEBO ■ pokud je jeden z argumentů proměnná (druhý ne), pak predikát neuspěje, NEBO ■ A i B jsou atomic a unifikovatelné NEBO ■ A i B jsou seznamy, pak jak jejich hlava tak jejich tělo mají stejnou strukturu NEBO ■ A i B jsou složené termy se stejným funktorem a jejich argumenty mají stejnou strukturu | ?- sameC[l,3,sinCX),sCa,3)],[l,3,sinCX),sCa,3)]). yes sameCA.B) :- varCA), varCB), !. sameCA.B) :- varCA), !, fail. sameCA.B) :- varCB), !, fail. sameCA.B) :- atomicCA), !, atomicCB), A==B. sameCA.B) :- atomicCB), !, fail. % jen kvůli vyšši efektivitě same C[HA|TA],[HB|TB]) :- !, sameCHA,HB), sameCTA.TB). sameCA.B) :- A=..[F|ArgA], B=..[F|ArgB], sameCArgA,ArgB). Hana Rudová, Logické programování I, 10. dubna 201 2 1 2 Vstup/výstup, databázové operace, rozklad termu D.Ú. unify(A,B) not_occurs(A,B) Napište predikát uni fy(A, B), který unifikuje termy A a B a provede zároveň kontrolu výskytu pomocí not_occurs(Var,Term). | ?- unify([Y,3,sin(a(3)),s(a,3)],[1,3,sin(X),s(a,3)]). X = a(3) Y = 1 yes unify(A,B) :- var(A), var(B), !, A=B. unify(A,B) :- var(A), !, not_occurs(A,B), A=B. unify(A,B) :- var(B), !, not_occurs(B,A), B=A. unify(A,B) :- atomic(A), atomic(B), !, A==B. unify(A,B) :- atomic(B), !, fail. unify([HA|TA],[HB|TB]) :- !, unify(HA,HB), unify(TA,TB). unify(A,B) :- A=..[F|ArgA], B=..[F|ArgB], unify(ArgA,ArgB) Hana Rudová, Logické programování I, 10. dubna 2012 Vstup/výstup, databázové operace, rozklad termu Predikát not_occurs(A, B) uspěje, pokud se proměnná A nevyskytuje v termu B. Tj. platí jedno z ■ B je atom nebo číslo NEBO ■ B je proměnná různá od A NEBO ■ B je seznam a A se nevyskytuje ani v těle ani v hlavě NEBO ■ B je složený term a A se nevyskytuje v jeho argumentech not_occurs(_,B) :- atomic(B), !. not_occurs(A,B) :- var(B), !, A\==B. not_occurs(A,[H|T]) :- !, not_occurs(A,H), not_occurs(A,T). not_occurs(A,B) :- B=..[_|Arg], not_occurs(A,Arg). Hana Rudová, Logické programování 1,10. dubna 201 2 Vstup/výstup, databázové operace, rozklad termu