Vstup/výstup, databázové operace, rozklad termu Ctení ze process_file( Soubor ) :- seeing( StarySoubor ), see( Soubor ), repeat, read( Term ), process_term( Term ), Term == end_of_file, i seen see( StarySoubor ). repeat. repeat :- repeat. souboru % zjištění aktivního proudu % otevrení souboru Soubor % čtení termu Term % manipulace s termem % je konec souboru? % uzavčrení souboru % aktivace původního proudu % vestavený predikát Hana Rudová, Logické programování I, 19. dubna 2011 2 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( 'Petrel' ), jdeme ]. A = ahoj, B = petre, C = ahoj('Petrel'), D = jdeme | ?- write(a(1)), write('.'), nl, write(a(2)), write('.'), nl. a(1). a(2). yes seeing, see, seen, read telling, tell, told, write -i* standardní vstupní a výstupní stream: user Hana Rudová, Logické programování I, 19. dubna 2011 3 Vstup/výstup, databázové operace, rozklad termu Příklad: vstup/výstup Napište predikát u1oz_do_souboru( Soubor ), který nacte několik fakt ze vstupu a uloží je do souboru Soubor. | ?- u1oz_do_souboru( 'soubor.pl' ). |: fakt(mirek, 18). |: fakt(pave1,4). |: end_of_fi1e. yes | ?- consult(soubor). % consulting /home/hanka/soubor.pl... % consulted /home/hanka/soubor.pl in module user, 0 msec % 376 bytes yes | ?- 1isting(fakt/2). % pozor:1isting/1 lze použít pouze pri consult/1 (ne u compile/1) fakt(mirek, 18). fakt(pave1, 4). yes Hana Rudová, Logické programování I, 19. dubna 2011 4 Vstup/výstup, databázové operace, rozklad termu Implementace: vstup/výstup uloz_do_souboru( Soubor ) :-seeing( StaryVstup ), telling( StaryVystup ), see( user ), tell( Soubor ), repeat, read( Term ), process_term( Term ), Term == end_of_file, i ■ > seen, told, tell( StaryVystup ), see( StaryVstup ). process_term(end_of_file) :- !. process_term( Term ) :- write( Term ), write('.'), nl. Hana Rudová, Logické programování I, 19. dubna 2011 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 explicitne (fakty) i implicitne (pravidly) JS> Vestavené predikáty pro zmenu databáze behem provádení programu: assertz( Klauzule ) pridání na konec retract( Klauzule ) smazání klauzule unifikovatelné s Klauzule JS> Pozor: retract/1 lze použít pouze pro dynamické klauzule (pridané pomocí assert) a ne pro statické klauzule z programu -i* Pozor: nadmerné použití techto operací snižuje srozumitelnost programu assert( Klauzule ) asserta( Klauzule ) pridání Klauzule do programu pridání na zacátek Hana Rudová, Logické programování I, 19. dubna 2011 6 Vstup/výstup, databázové operace, rozklad termu Databázové operace: příklad Napište predikát vytvor_program/0, který nacte několik klauzulí ze vstupu a uloží je do programové databáze. | ?- vytvor_program. |: fakt(pavel, 4). |: pravidlo(X,Y) :- fakt(X,Y). |: end_of_file. yes | ?- listing(fakt/2). fakt(pavel, 4). yes | ?- listing(pravidlo/2). pravidlo(A, B) :- fakt(A, B). yes | ?- clause( pravidlo(A,B), C). % clause/2 použitelný pouze pro dynamické klauzule C = fakt(A,B) ? yes Hana Rudová, Logické programování I, 19. dubna 2011 7 Vstup/výstup, databázové operace, rozklad termu Databázové operace: implementace vytvor_program :- seeing( StaryVstup ), see( user ), repeat, read( Term ), uloz_term( Term ), Term == end_of_file, i ■ > seen, see( StaryVstup ). uloz_term( end_of_file ) :- !. uloz_term( Term ) :- assert( Term ). Hana Rudová, Logické programování I, 19. dubna 2011 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 nekteré argumenty, pak je efektivnejší: functor( Term, Funktor, Arita ) functor( a(9,e), a, 2 ) functor(atom,atom,0) i functor(1,1,0) arg( 2, a(9,e), e) arg( N, Term, Argument ) Hana Rudová, Logické programování I, 19. dubna 2011 9 Vstup/výstup, databázové operace, rozklad termu Rekurzivní rozklad termu -i* Term je seznam ([_|_]) => procházení seznamu a rozklad každého prvku seznamu ii> Term je složený (=../2, functor/3) => procházení seznamu argumentu a rozklad každého argumentu JS> Príklad: ground/1 uspeje, pokud v termu nejsou promenné; jinak neuspeje ground(Term) :- atomic(Term), !. % Term je atom nebo Číslo NEBO ground(Term) :- var(Term), !, fail. % Term není promenná NEBO ground([H|T]) :- !, ground(H), ground(T). % Term je seznam a ani hlava ani telo % neobsahují promenné NEBO ground(Term) :- Term =.. [ _Funktor | Argumenty ], % je Term složený ground( Argumenty ). % a jeho argumenty % neobsahují promenné ?- ground(s(2,[a(1,3),b,c],X)). ?- ground(s(2,[a(1,3),b,c])). Hana no Rudová, Logické programování I, 19. dubna 2011 10 yes 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áve term T NEBO podterm S se nachází v hlave seznamu T NEBO & podterm S se nachází v tele seznamu T NEBO JS> T je složený term (compound/1) a S je podtermem nekterého argumentu T J> otestujte :- subterm(1,2). pokud nepoužijeme (compound/1), pak tento dotaz cyklí otestujte :- subterm(a,[1,2]). overte, zda necyklí (nutný cervený rez níže) | ?- subterm(sin(3),b(c,2,[1,b],sin(3),a)). yes Hana Rudová, Logické programování I, 19. dubna 2011 11 Vstup/výstup, databázové operace, rozklad termu subterm(S,T) Napište predikát subterm(S,T) pro termy S a T bez promenných, které uspejí, pokud je S podtermem termu T. Tj. musí platit alespon jedno z & podterm S je práve term T NEBO podterm S se nachází v hlave seznamu T NEBO & podterm S se nachází v tele seznamu T NEBO JS> T je složený term (compound/1) a S je podtermem nekterého argumentu T & otestujte :- subterm(1,2). pokud nepoužijeme (compound/1), pak tento dotaz cyklí otestujte :- subterm(a,[1,2]). overte, zda necyklí (nutný cervený rez níže) | ?- subterm(sin(3),b(c,2,[1,b],sin(3),a)). yes subterm(T,T) :- !. subterm(S,[H|_]) :- subterm(S,H), !. subterm(S,[_|T]) :- !, subterm(S,T). subterm(S,T) :- compound(T), T=..[_|Argumenty], subterm(S,Argumenty). Hana Rudová, Logické programování I, 19. dubna 2011 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áve jedno z JS* A i B jsou promenné NEBO pokud je jeden z argumentu promenná (druhý ne), pak predikát neuspeje, NEBO -Ä* A i B jsou atomic a unifikovatelné NEBO & A i B jsou seznamy, pak jak jejich hlava tak jejich telo mají stejnou strukturu NEBO J5> A i B jsou složené termy se stejným funktorem a jejich argumenty mají stejnou strukturu | ?- same([1,3,sin(X),s(a,3)],[1,3,sin(X),s(a,3)]). yes Hana Rudová, Logické programování I, 19. dubna 2011 12 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áve jedno z JS* A i B jsou promenné NEBO pokud je jeden z argumentu promenná (druhý ne), pak predikát neuspeje, NEBO -Ä* A i B jsou atomic a unifikovatelné NEBO & A i B jsou seznamy, pak jak jejich hlava tak jejich telo mají stejnou strukturu NEBO J5> A i B jsou složené termy se stejným funktorem a jejich argumenty mají stejnou strukturu | ?- same([1,3,sin(X),s(a,3)],[1,3,sin(X),s(a,3)]). yes same(A,B) :- var(A), var(B), 1. same(A,B) :- var(A), 1, fail. same(A,B) :- var(B), 1, fail. same(A,B) :- atomic(A), atomic(B), 1, A==B. same([HA|TA],[HB|TB]) :- 1, same(HA,HB), same(TA,TB). same(A,B) :- A=..[F|ArgA], B=..[F|ArgB], same(ArgA,ArgB). Hana Rudová, Logické programování I, 19. dubna 2011 12 Vstup/výstup, databázové operace, rozklad termu D.Ú. unify(A,B) Napište predikát unify(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 Hana Rudová, Logické programování I, 19. dubna 2011 13 Vstup/výstup, databázové operace, rozklad termu D.Ú. unify(A,B) Napište predikát unify(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([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, 19. dubna 2011 13 Vstup/výstup, databázové operace, rozklad termu not_occurs(A,B) 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 císlo NEBO JS> B je promenná různá od A NEBO & B je seznam a A se nevyskytuje ani v tele ani v hlave NEBO B je složený term a A se nevyskytuje v jeho argumentech Hana Rudová, Logické programování I, 19. dubna 2011 14 Vstup/výstup, databázové operace, rozklad termu not_occurs(A,B) Predikát not_occurs(A,B) uspeje, pokud se promenná A nevyskytuje v termu B. Tj. platí jedno z & B je atom nebo císlo NEBO JS> B je promenná různá od A NEBO & B je seznam a A se nevyskytuje ani v tele ani v hlave 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í I, 19. dubna 2011 14 Vstup/výstup, databázové operace, rozklad termu