:- ensure_loaded(typeops_meta).

% examples with fold operations
%
% foldl/4 predicate
%   foldl(op, b, [e1, e2, ..., en], ((...((b op e1) op e2)...) op en))
% 
% natural_number(X) :- X is a natural number.
%
% plus(X,Y,Z) :-
%	X, Y and Z are natural numbers
%	such that Z is the sum of X and Y.
%
% times(X,Y,Z) :-
%	X, Y and Z are natural numbers
%	such that Z is the product of X and Y
%

 
%+++++++++++++++++++++++++++++ type definitions +++++++++++++++++++++++ 

:- import_type(prolog_types).

:- suptype numexpr2 > numexpr.
:- type numexpr2 --> numexpr2 mod numexpr2.

:- type nats0 --> s(nats0); 0.
 
%+++++++++++++++++++++++++++++ predicates  +++++++++++++++++++++++ 

:- import_pred(prolog_meta,fcall/4).
:- import_pred(prolog_meta,fcall/3).
:- import_pred(prolog_meta,fcall/2).

:- import_pred(prolog_meta,'>='/2).
:- import_pred(prolog_meta,'=<'/2).
:- import_pred(prolog_meta,'>'/2).
:- import_pred(prolog_meta,'='/2).
:- import_pred(prolog_meta,!/0).
:- import_pred(prolog_meta,is/2).


:- pred foldl(meta((trmName(@T1, @T, @T1) of mpred)), T1, list(T), @T2)
          with T1 =< T2.
foldl(_F, B, [], B).
foldl(F, Bs, [A|As], Cs) :-
	fcall(F, Bs, A, Bs1),
	foldl(F, Bs1, As, Cs).


:- pred map(meta((trmName(@T1,@T2) of mpred)), list(T1), list(T2)).
map(_F,[],[]).
map(F, [A0|As0], [A|As]) :-
	fcall(F,A0,A),
	map(F,As0,As).


:- pred natural_number(nats0).
natural_number(0).
natural_number(s(X)) :- natural_number(X).


:- pred plus(nats0, nats0, nats0).
plus(0,X,X) :- natural_number(X).
plus(s(X),Y,s(Z)):- plus(X,Y,Z).


:- pred times(nats0, nats0, nats0).
times(0,_X,0).
times(s(X),Y,Z) :- times(X,Y,XY), plus(XY,Y,Z).

:- pred times_seven(nats0, nats0).
times_seven(Y,Z) :- trans_nat_numb(7, X),
	            times(X, Y, Z).

:- pred trans_nat_numb(nat, nats0).
trans_nat_numb(0, 0) :- !.
trans_nat_numb(X, s(Y)) :- X_new is X - 1, trans_nat_numb(X_new, Y).

:- pred trans_numb_nat(nats0, nat).
trans_numb_nat(0, 0) :- !.
trans_numb_nat(s(Y), X) :- trans_numb_nat(Y, X_old), X is X_old + 1.

%+++++++++++++++++++++++++++++ tests  ++++++++++++++++++++++++++ 


?- map(trans_nat_numb,[1,2,3,4], Numbs), 
   map(times_seven, Numbs, Xs),
   foldl(plus, 0, Xs, Y),
   trans_numb_nat(Y,Z).







