% 
% 		     Deklaratív Programozás gyakorlat
% 		Prolog programozás: meta-logikai eljárások

% 

% 1.  Atomok szeletelése

%     Egy A atom prefixumának nevezünk egy P atomot, ha P az A első 
%     valahány karakterét tartalmazza, az A-beli sorrend megtartásával.

%     % atom_prefix(+Atom, ?Prefix, +N): Atom-nak Prefix N hosszú prefixuma.
%     % Másszóval: az Atom első N karakteréből képzett névkonstans a Prefix atom.
    
%     | ?- atom_prefix(abcde, Prefix, 0).
%     Prefix = '' ? ; no
%     | ?- atom_prefix(abcde, Prefix, 3).
%     Prefix = abc ? ; no
%     | ?- atom_prefix(abcde, Prefix, 5).
%     Prefix = abcde ? ; no
%     | ?- atom_prefix(abcde, Prefix, 6).
%     no

%     Nem használhatja a sub_atom/5 beépített eljárást!
%     Ötlet: használja az atom_codes és prefix_length eljárásokat.

:- use_module(library(lists)).

atom_prefix(Atom, Prefix, N) :-
	atom_codes(Atom, Codes),
	prefix_length(Codes, Prefix_Codes, N),
	atom_codes(Prefix, Prefix_Codes).




% 2.  Általános Prolog kifejezés részkifejezéseinek vizsgálata
% 
%     % mern(+K, +N): A K általános Prolog kifejezésben előforduló összes
%     % egész szám határozottan nagyobb mint N 
%     % (mern = minden egész részkifejezése nagyobb mint)
% 
%     | ?- mern(1, 1).
%     no
%     | ?- mern(1, 0).
%     yes
%     | ?- mern(0.0, 1).
%     yes
%     | ?- mern(f(X,[1,3,b],g(2,1,3)), 0).
%     yes
%     | ?- mern(f(X,[1,3,b],g(2,1,3)), 1).
%     no
% 
% Megjegyzések:
% 
%     a. A "K1 Prolog kifejezésben előfordul a K2 kifejezés" relációt
%        reflexívnek tekintjük, azaz egy K kifejezésben önmaga mindenképpen
%        előfordul. Ez a megjegyzés vonatkozik az ezután következő
%        feladatokra is.
%     b. Vigyázzon arra, hogy a kifejezésben változók is előfordulhatnak.

mern(K, N) :-
	(   integer(K) ->
	    K > N
	;   compound(K) -> 
	    K =.. [_Fun|Args], 
	    mern_lista(Args, N)
	;   true 
	).


mern_rossz(K, N) :-
	(   integer(K) ->
	    K > N
	;   compound(K) -> 
	    K =.. [_Fun|Args], 
	    mern_rossz(Args, N)
	;   true 
	).

% | ?- trace, mern_rossz(f(1), 0).
% % The debugger will first creep -- showing everything (trace)
%         1      1 Call: mern_rossz(f(1),0) ? 
%         2      2 Call: mern_rossz([1],0) ? 
%         3      3 Call: mern_rossz([1,[]],0) ? 
%         4      4 Call: mern_rossz([1,[[]]],0) ? 
%         5      5 Call: mern_rossz([1,[[[]]]],0) ? 
%         6      6 Call: mern_rossz([1,[[[[]]]]],0) ? 
%         7      7 Call: mern_rossz([1,[[[[[]]]]]],0) ? 
%         8      8 Call: mern_rossz([1,[[[[[[]]]]]]],0) ? 
%         9      9 Call: mern_rossz([1,[[[[[[[]]]]]]]],0) ? 
%        10     10 Call: mern_rossz([1,[[[[[[[[]]]]]]]]],0) ? 
%        11     11 Call: mern_rossz([1,[[[[[[[[...]]]]]]]]],0) ? 
%        12     12 Call: mern_rossz([1,[[[[[[[[...]]]]]]]]],0) ? 
%        13     13 Call: mern_rossz([1,[[[[[[[[...]]]]]]]]],0) ? 
%        14     14 Call: mern_rossz([1,[[[[[[[[...]]]]]]]]],0) ? 


% mern_lista(+Ks,+N): a Ks listában szereplo minden kifejezésben minden
% egész nagyobb, mint N.
mern_lista([], _N).
mern_lista([K|Ks], N) :-
	mern(K,N), 
	mern_lista(Ks, N).

% mern_lista2(+L,+N): az L listának nincs olyan X eleme, amelyre nem teljesül 
% hogy X-ben szereplő minden egész nagyobb mint N.
mern_lista2(L, N) :-
	\+ (   member(X, L), \+ mern(X, N)
	   ).


% 3.  Általános Prolog kifejezés bizonyos részkifejezéseinek felsorolása
% 
%     % reszatom(+K, ?A): A a K általános Prolog kifejezésben
%     % előforduló atom. 
% 
%     | ?- reszatom(a, X).
%     X = a ? ;
%     no
%     | ?- reszatom(f(X,[1,3,b],g(2,1,a0)), A).
%     A = b ? ;
%     A = [] ? ;
%     A = a0 ? ;
%     no
% 
%     Megjegyzés: a struktúranevet nem tekintjük a struktúrakifejezés
%     részének.

reszatom0(K, A) :-
	(   atom(K) -> 
	    K = A
	;   compound(K) -> 
	    K =.. [_Fun|Args],
	    lista_reszatom(Args, A)
	).

% Lista_reszatom(+L, ?A): A az L lista egy elemében előforduló atom. 
lista_reszatom(Args, A) :-
	member(Arg, Args), 
	reszatom0(Arg, A).


reszatom_rossz(K, A) :-
	(   atom(K) -> 
	    K = A
	;   compound(K) -> 
	    K =.. [_Fun|Args],
	    reszatom_rossz(Args, A)
	).

% | ?- trace, reszatom_rossz(f(a), A).
% % The debugger will first creep -- showing everything (trace)
%         1      1 Call: reszatom_rossz(f(a),_933) ? 
%         2      2 Call: reszatom_rossz([a],_933) ? 
%         3      3 Call: reszatom_rossz([a,[]],_933) ? 
%         4      4 Call: reszatom_rossz([a,[[]]],_933) ? 
%         5      5 Call: reszatom_rossz([a,[[[]]]],_933) ? 
%         6      6 Call: reszatom_rossz([a,[[[[]]]]],_933) ? 
%         7      7 Call: reszatom_rossz([a,[[[[[]]]]]],_933) ? 
%         8      8 Call: reszatom_rossz([a,[[[[[[]]]]]]],_933) ? 
%         9      9 Call: reszatom_rossz([a,[[[[[[[]]]]]]]],_933) ? 
%        10     10 Call: reszatom_rossz([a,[[[[[[[[]]]]]]]]],_933) ? 
%        11     11 Call: reszatom_rossz([a,[[[[[[[[...]]]]]]]]],_933) ? 
%        12     12 Call: reszatom_rossz([a,[[[[[[[[...]]]]]]]]],_933) ? 
%        13     13 Call: reszatom_rossz([a,[[[[[[[[...]]]]]]]]],_933) ? 

reszatom(K, A) :-
	(   atom(K) -> 
	    K = A
	;   compound(K) -> 
	    K =.. [_Fun|Args],
	    member(Arg, Args), 
	    reszatom(Arg, A)
	).





% 4.  Általános Prolog kifejezés bizonyos részkifejezéseinek akkumulálása
% 
%     % osszege(+K, ?Ossz): Ossz a K kifejezésben előforduló egész számok
%     % összege.
% 
%     | ?- osszege(a, S).
%     S = 0 ? ;
%     no
%     | ?- osszege(1, S).
%     S = 1 ? ;
%     no
%     | ?- osszege(f(X,[1,3,b],g(2,1,a0)), S).
%     S = 7 ? ;
%     no

osszege(K, Sum) :-
        osszege(K, 0, Sum).

% a K kifejezésben előforduló egész számok összege + Sum0 = Sum.
osszege(K, Sum0, Sum) :-
	(   integer(K) -> 
	    Sum = Sum0+K
	;   compound(K) -> 
	    K =.. [_Fun|Args], 
	    osszege_lista(Args, Sum0, Sum)
	;   Sum = Sum0
	).

% osszege_lista(+KL, +Ossz0, ?Ossz): A KL listában előforduló egész számok
% összege plusz az Ossz0 szám egyenlő az Ossz számmal.
osszege_lista([], Sum, Sum).
osszege_lista([X0|L0], Sum0, Sum) :-
	osszege(X0, Sum1),
	Sum2 is Sum0+Sum1,
	osszege_lista(L0, Sum2, Sum).


helyettesitese(K, HL, E) :-
	(   number(K) -> E = K
	;   atom(K),
	    (   memberchk(K-E, HL) -> true
	    ;   E = 0
	    )
	).

helyettesitese2(K, _, K) :-
	number(K).
helyettesitese2(K, [M-Sz|HL], E) :-
	atom(K),
	(   K = M -> E = Sz
	;   helyettesitese2(K, HL, E)
	).
helyettesitese2(K, [], 0) :-
	atom(K).

	
erteke(K, HL, E) :-
	(   atomic(K) -> helyettesitese(K, HL, E)
	;   K =.. [Op,A1] ->
	    erteke(A1, HL, A1E),
	    EKif =.. [Op,A1E],
	    E is EKif
	;   K =.. [Op,A1,A2] ->
	    erteke(A1, HL, A1E),
	    erteke(A2, HL, A2E),
	    EKif =.. [Op,A1E,A2E],
	    E is EKif
	).


erteke2(K, HL, E) :-
	(   atom(K) -> 
	    (   memberchk(K-V, HL) -> E = V
	    ;   E = 0
	    )
	;   number(K) -> E = K
	;   K =.. [Op,A1] ->
	    erteke2(A1, HL, A1E),
	    EKif =.. [Op,A1E],
	    E is EKif
	;   K =.. [Op,A1,A2] ->
	    erteke2(A1, HL, A1E),
	    erteke2(A2, HL, A2E),
	    EKif =.. [Op,A1E,A2E],
	    E is EKif
	).
