
:- op(700, xfx, \=).
A \= B :- \+ A = B.					% Define `\='

% ======================================================================
%	For Demoing the execution of goals:
% ======================================================================

demo_goals([]).
demo_goals([Goal|Goals]) :- demo_goal(Goal), demo_goals(Goals).

demo_goal(Pred) :-
	Pred \= _-_-_,
	write('| ?- '), pretty_write(Pred), write('.'), getnl,
	call(Pred), !,
	nl, write(yes), nl.
demo_goal(Pred-Vars-Style) :-
	copy(Pred-Vars, CPred-CVars),
	assign_names(CVars),
	write('| ?- '), pretty_write(CPred), write('.'), getnl,
	call(Pred),
	nl, show_vars(CVars, Vars), 
	( Style = allsolns -> write(' ;'), getnl, fail ; nl, nl ),
	!.
demo_goal(_) :-
	nl, write(no), nl.

assign_names([]).
assign_names([Var/Name|Vars]) :- Var=Name, assign_names(Vars).

show_vars([V/_], [Val/_]) :- !,
	write(V), write(' = '), write(Val).
show_vars([V/_|Vs], [Val/_|Vals]) :-
	write(V), write(' = '), write(Val), write(','), nl,
	show_vars(Vs, Vals).

getnl :- repeat, get0(NL), is_nl_char(NL), !.

is_nl_char(10).

% -------------------- Pretty term writing facility --------------------

pretty_write(Term) :- underscore_vars(Term), write(Term), fail.
pretty_write(_).

underscore_vars(Term) :-
	bagof_variables(Term, Vars),
	underscore_vars(Vars, Vars),
	numbervars(Term, 0, _).

underscore_vars([], _).
underscore_vars([V|Vs], AllVs) :- 
	unique_var(V, AllVs), !, 
	V = '_', 
	underscore_vars(Vs, AllVs).
underscore_vars([_|Vs], AllVs) :-
	underscore_vars(Vs, AllVs).

unique_var(Var, Vars) :-
	eq_remove(Var, Vars, RestVars),
	\+ eq_remove(Var, RestVars, _),
	!.

bagof_variables(Term, Vlist) :-
	bagof_variables(Term, [], Vlist).

bagof_variables(V, Sofar, [V|Sofar]) :- var(V), !.
bagof_variables(A, Sofar,    Sofar ) :- atomic(A), !.
bagof_variables([HD|TL], Sofar, Result) :- !,
	bagof_variables(HD, Sofar, Inter),
	bagof_variables(TL, Inter, Result).
bagof_variables(Term, Sofar, Result) :-
	Term =.. [_|Args],
	bagof_variables(Args, Sofar, Result).

eq_remove(A, [C|B], B) :- A == C, !.
eq_remove(A, [C|B], [C|NewB]) :- eq_remove(A, B, NewB).

% -----------------------------------------------------------------

% Copied from library(types), renamed ground/1 -> is_ground/1 to avoid
% illegal re-definition errors when running under Q3.*
% is_ground(+Term). Succeeds if Term contains no variables
is_ground(Term) :- nonvar(Term), functor(Term,_,Arity), is_ground(Arity,Term).

is_ground(0, _) :- !.
is_ground(N, Term) :-
    	arg(N, Term, Arg), nonvar(Arg), functor(Arg, _, Arity),
	is_ground(Arity, Arg), M is N-1, is_ground(M, Term).

% ----------------------------------------------------------------------

:- dynamic 'gensym counter'/2.

gensym(Prefix, Sym) :-
	( retract('gensym counter'(Prefix,OldN)) -> true ; OldN = 0 ),
	N is OldN + 1,
	assertz('gensym counter'(Prefix,N)),
	number_chars(N, NCh),
	atom_chars(Prefix, PCh),
	myappend(PCh, NCh, SymCh),
	atom_chars(Sym, SymCh).

% same as append/3: call this myappend/3 so as not to clash with built-in
% append/3 under Quintus3.1.1.
myappend([], A, A).
myappend([A|B], C, [A|D]) :- myappend(B, C, D).

member(X, [X|_]).
member(X, [_|Y]) :- member(X, Y).

memberchk(X, [X|_]) :- !.
memberchk(X, [_|Y]) :- memberchk(X, Y).

% From library(sets)
union([], Union, Union).
union([Element|Elements], Set, Union) :-
	memberchk(Element, Set),
	!,
	union(Elements, Set, Union).
union([Element|Elements], Set, [Element|Union]) :-
	union(Elements, Set, Union).

% nlist(5, X)	=>  X = [1,2,3,4,5]
nlist(N, []) :- N < 1, !.
nlist(N, List) :- nlist(1, N, List).

nlist(N, N, [N]) :- !.
nlist(N, Max, [N|Ns]) :- NewN is N + 1, nlist(NewN, Max, Ns).

nmemberchk(Elem, List, N) :- nmember(Elem, List, N), !.

nmember(Elem, List, N) :-
	nmember(Elem, List, 1, N).

nmember(Elem, [Elem|_], N, N).
nmember(Elem, [_|List], NSoFar, N) :-
	NewN is NSoFar + 1,
	nmember(Elem, List, NewN, N).

append([], []).					% library(lists)
append([L|Ls], List0) :-
	myappend(L, List1, List0),
	append(Ls, List1).

% ======================================================================
%		COPYING A PROLOG TERM

% Rather crude copying mechanism, but works
% copy(A, CopyA) :- asserta('copy of'(A)), retract('copy of'(CopyA)), !.

% Faster:
copy(In, Out) :- copy(In, Out, _, []).

% Copy (In) to (Out) keeping track of the variables
copy(In, Out,         Swaps , Swaps  ) :- var(In), vmem(In/Out, Swaps), !.
copy(In, Out, [In/Out|Swaps], Swaps  ) :- var(In), !, var(Out).
copy(In, Out,       SwapsOut, SwapsIn) :-
	functor(In, F, N),
	functor(Out, F, N),
	copy_args(N, In, Out, SwapsOut, SwapsIn).

copy_args(0, _, _, S, S) :- !.
copy_args(N, In, Out, Sout, Sin) :-
	arg(N, In, InN),
	arg(N, Out, OutN),
	copy(InN, OutN, Sinter, Sin),
	N1 is N-1,
	copy_args(N1, In, Out, Sout, Sinter).

vmem(A/B, [Am/B|_]) :- A == Am, !.
vmem(  X, [   _|R]) :- vmem(X, R).



