:- dynamic([diverge/0,member_/2,append_/3,insert/3,perm/2]). 

% test(+P, -D, -G, -N, -J)
% test a single atom goal P = p(ts) which does not depend on others
% D = reified program for p, G = reified goal, N = next free variable
% J = success or failure
test(P, D, G, N, J) :-
	P =.. [Pred|Xs],
	length(Xs, Arity),
	reify(Pred/Arity, D),
	reify_goal(P, G, N),			% N-1 = # of free vars in goal
	solve(G, [prog(Pred/Arity, D)], N, J).

test2([], Gamma, A, J) :-
	reify_goal(A, G, N),
	solve(G, Gamma, N, J).

test2([Pred/Arity|Preds], Gamma, A, J) :-
	reify(Pred/Arity, D),
	test2(Preds, [prog(Pred/Arity, D)|Gamma], A, J).

% test2([Pred1/Arity1, ..., Predn/Arityn], A, J)
% reify Pred1...Predn, solve goal A, J = success or failure, backtrackable
test2(Preds, A, J) :- test2(Preds, [], A, J).

/*
test(member_(1, [2,1,3]), D, G, N, J).
test(member_(1, [2,4,3]), D, G, N, J).
test(member_(X, [1,2,3,4]), D, G, N, J).
test(append_([1,2],[3,4],[1,2,3,4]), D, G, N, J).
test(append_([1,2],[3,4],Zs), D, G, N, J).
test(append_(Xs, Ys, [1,2,3,4]), D, G, N, J).
test2([insert/3],insert(1, [1,2,3], Zs), J).
test2([perm/2,insert/3], perm([1,2,3], _), J).
*/
% Test predicates
% All test predicates must be declared dynamic

% member_(X, Ys) iff X is a member of the list Ys
% will succeed multiple times for each member of Ys equal to X.
member_(X, [X|_]).
member_(X, [_|Ys]) :- member_(X, Ys).

% append_(Xs, Ys, Zs) iff Zs is the result of appending list Ys to list Xs
append_([], Ys, Ys).
append_([X|Xs], Ys, [X|Zs]) :- append_(Xs, Ys, Zs). 

% insert(X, Ys, Zs) iff Zs is result of insert X somewhere in Ys
insert(X, Ys, [X|Ys]).
insert(X, [Y|Ys], [Y|Zs]) :- insert(X, Ys, Zs). 

% perm(Xs, Zs) iff Zs is a permutation of Xs
perm([], []).
perm([X|Xs], Zs) :-
	perm(Xs, Ys),
	insert(X, Ys, Zs).

% diverge will never terminate
diverge :- diverge ; true.
