
% priklady na procviceni

delete(X,[X|T],T).
delete(X,[Y|T],[Y|NT]):-delete(X,T,NT).

% kombinace s opakovanim
% comb_rep(+N,+L,-Lout) - vypise do Lout vsechny podseznamy L o delce N. Prvky se mohou opakovat a nezalezi na poradi
comb_rep(0,_,[]).
comb_rep(N,[X|T],[X|RComb]):-N>0,N1 is N-1,comb_rep(N1,[X|T],RComb).
comb_rep(N,[_|T],RComb):-N>0,comb_rep(N,T,RComb).

% variace s opakovanim
% varia_rep(+N,+L,-Lout) - vypise do Lout vsechny podseznamy L o delce N. Prvky se mohou opakovat a zalezi na poradi
varia_rep(0,_,[]).
varia_rep(N,L,[H|RVaria]):-N>0,N1 is N-1,delete(H,L,_),varia_rep(N1,L,RVaria).

% trik: vypsani vsech reseni
% pouzijeme fail a ono to bude vypisovat a snazit se hledat reseni, ktere nas uspokoji, lec takove neni

vypiskombinace(N,L):-comb_rep(N,L,Lout),write(Lout),nl,fail.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% operatory
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% v prologu je mozne definovat si vlastni operatory
:-op(600,xfx, ma).
:-op(700,xfx, a).

% prvni argument znaci prioritu. Cim nizssi, tim vetsi ma operator prioritu. Rozsah 1-1200
% druhy argument odpovida, zda se jedna o infixni (a tedy dvojargumentovy), prefixni ci postfixni (a tedy jednoargumentovy).
% treti argument je samotny nazev operatoru. Muze jich byt vic, pak jsou v seznamu
% pozn. pokud je prikaz :- bez hlavy, uspeje tato klauzule hned pri nacteni databaze a "provede" se, da se to pouzit pro "spustitelne" soubory
% muzeme je pak v databazi libovolne pouzivat
mama ma maso.
mama ma ema.
% operatorum neni implicitne prirazovana zadna semantika (az na par vestavenych vyjimek), vsechno si musime zadefinovat sami.
% jsou tri skupiny operatoru
% 1) infixni
% xfx xfy yfx
% 2) prefixni
% fx fy
% 3) postfixni
% xf yf
% f odpovida operatoru
% vyznam x nebo y se lisi dle priority. Je-li vyraz v zavorkach nebo se jedna o nestrukturovany objekt, je jeho priorita 0, jinak odpovida priorite funktoru
% x odpovida tomu, ze ma mit vyraz ostre mensi prioritu, nez operator, y muze mit i rovnou
% prolog tedy spravne pozna, jak vytvorit tento vyraz
% 11 is 2 + 3 * 3 .... is(11,+(2,*(3,3)))
:-op(300,xfx,hraje).
:-op(200,xfy,a).
petr hraje fotbal a hokej a tenis.
% ?- hraje(petr,a(fotbal,a(hokej,tenis)))=petr hraje fotbal a hokej a tenis.
% napriklad a-b-c se standardne cte jako (a-b)-c, pokud bychom chteli a-(b-c), tak bychom to museli zadefinovat jako xfy
% namalovat strom
% to same pro negaci ~, mame-li negaci zadefinovanou jako fy, je ~~p ok, pokud bychom meli fx, tak to neprojde, protoze priorita vnirniho operatoru je stejna jako vnejsiho
% operatory se hodi pro vetsi citelnost kodu
% nektere standardni operatory
% :- op( 1200, xfx, [ :-, --> ]).
% :- op( 1200,  fx, [ :-, ?- ]).
% :- op( 1100, xfy, [ ; ]).
% :- op( 1000, xfy, [ ',' ]). % tady musi byt v argumentech, protoze jinak by bral caru jako oddelovac prvku seznamu
% :- op(  700, xfx, [ =, is, =.., ==, \==, =:=, =\=, <, >, =<, >= ]).
% :- op(  500, yfx, [ +, -]).
% :- op(  500,  fx, [ +, - ]).
% :- op(  300, xfx, [ mod ]).
% :- op(  200, xfy, [ ^ ]).

% pozor, zalezi na poradi!

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Prace s termy
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% term muzeme rozkladat (a inverzne sestavovat) do seznamu
% operator T =.. L rozlozi term T do seznamu L, kde jako prvni prvek seznamu L bude jmeno T a jako dalsi prvky budou argumenty T
% f(a,b)..=L.
% L=[f,a,b]
% je to obousmerne
% T=[ctverec,X]
% T=ctverec(X)
% muze se to hodit napriklad v pripade, ze mame funkci, ktera neco provadi s parametry nezavisle na objektu
% Pr:
% mejme predikaty ctverec(Strana), trojuhelnik(Strana1,Strana2,Strana3) a kruh(Polomer)
% dale mame predikat zvetsi(Objekt,N,Objekt2), ktery vynasobi vsechny rozmery objektu N-krat
% museli bychom mit tri relace pro kazdy objekt - zvetsi(ctverec(S),N,ctverec(S2)):-S2 is S*N,...
% muzeme to ale udelat uplne obecne pomoci predikatu =..
zvetsi(Obj1,N,Obj2):-
	Obj1=..[Typ|P1],
	vynasobseznam(P1,N,P2), % to proste vynasobi Nkem kazdy prvek Parametry
	Obj2=..[Typ|P2].
% takto vytovrene termy muzeme normalne zavolat
% T=..[append,[a,b],[d,e],L],call(T).

% nekdy nas zajima pouze nazev termu nebo nejaky z argumentu, pak se hodi functor/3 a arg/3
% functor(T,F,N) - uspeje, pokud F je funkcni symbol T a N je pocet argumentu T
% arg(N,T,A) - uspeje, pokud A je Ntym argumentem T

% logicke spojky
:- op(300,fx,~).
:- op(400,xfy,/\).
:- op(350,xfy,\/).
:- op(600,xfx,=>).
:- op(650,xfx,<=>).

% operator valuace
:- op(500,xfx,/).

% tt je pravdivostni tabulka pro obecne n-arni logicke fce, pricemz na prvnim miste je symbol, na druhem vystupni hodnota a na dalsim jsou argumenty log. operatoru

% nektere standardni
% not
tt(~,0,1).
tt(~,1,0).
% or
tt(\/,0,0,0).
tt(\/,1,0,1).
tt(\/,1,1,0).
tt(\/,1,1,1).
% and
tt(/\,1,1,1).
tt(/\,0,0,1).
tt(/\,0,1,0).
tt(/\,0,0,0).
% eq
tt(<=>,1,0,0).
tt(<=>,0,0,1).
tt(<=>,0,1,0).
tt(<=>,1,1,1).
% impl
tt(=>,1,0,0).
tt(=>,1,0,1).
tt(=>,0,1,0).
tt(=>,1,1,1).

wff(A):-(var(A);atom(A)),!.
wff(~A):-wff(A).
wff(A):-(A=B \/ C;A=B /\ C;A=B => C;A=B <=> C),wff(B),wff(C),!.

% rozmyslet si predikat model(F,V,B), ktery unifikuje B=1, pokud V je modelem F a B=0 jinak
% napiste tuto metodu obecne pro libovolne log. funkce (tj. pres operator dekompozice)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Rezy
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


% zeleny rez - zahazuje reseni, ktera nemaji smysl
% member(X, [X|_]):- !.
% member(X, [_|Xs]):- member(X, Xs).

% zeleny rez - max
%   max(X,Y,X)  :-  X  >  Y,!. 
%   max(X,Y,Y)  :-  X<=Y.
% tohle je ok, to nam nic neubira

% je tam k necemu telo druhe klauzule?
% cerveny rez - pri spatnem volani muze vracet spatna reseni, zalezi na poradi predikatu, meni deklarativni vyznam programu..
% max(X, Y, X):- X > Y, !.
% max(X, Y, Y).
% max(2,3,3) uspeje, coz je divne..

% lepe..
% max(X, Y, Z):- X > Y, !,Y=Z.
% max(X, Y, Y).



% to same 
deleteall(_,[],[]).
 deleteall(X,[X|Y],Z) :- !, deleteall(X,Y,Z).
 deleteall(X,[Q|Y],[Q|Z]) :- deleteall(X,Y,Z).


% jak se rezy chovaji
% uvazujme nasledujici znalostni bazi
% s(a).              p(X,Y):- l(X).
% s(b).              p(X,Y):- r(X),!,.....
% r(a).              p(X,Y):- m(X)........
% r(b).
% potom pri dotazu ?-s(A), p(B, C). se nebude prochazet cast stromu 

% not vypada nasledovne
% not(p) :- call(p),!,fail.
% not(p).
% pozor, neni to klasicka negace
hotel_obsazen :-not(volnı_pokoj(_)).
volny_pokoj(13).
volny_pokoj(313).
% neumoznuje dotazy typu ktere pokoje nejsou volne
% human(petr).
% not(human(marie)).

% not spise pro testovani
% da se pouzit operator \+
% ?- hotel_obsazen. 
% no
% ?- not(hotel_obsazen). 
% yes
% ?-volny_pokoj(X). 
% X = 13;
% X = 313; 
% no

% uzitecny predikat
% once(G):- G,!.
% zavola G a nebacktrackuje

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% standardni usporadani termu
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% termy jsou standardne usporadane:
% Promenne < Cisla < Atomy < Retezce < Struktury
% pro usporadani termu mame operatory @<,@=<,@>,@>=
% == a \== porovnavaji take lexikograficky
% atomy a retezce jsou porovnavany lexikograficky, cisla podle hodnoty, promenne podle interniho ciselniku a slozene strukury rekurzivne
% napr:
% ?- 'a'@>a.  true.
% ?- X@>a.  false.