true.

X = X.

X /= X :- !, fail.
X /= Y.

P -> Q :- P, !, Q.

P -> Q | R :- P, !, Q.
P -> Q | R :- !, R.

X | Y :- X.
X | Y :- Y.

P -> Q; R :- P, !, Q.
P -> Q; R :- !, R.

X;Y :- X.
X;Y :- Y.

(X, Y) :- X, Y.

not(X) :- X, !, fail.
not(X).

Compterm =.. Termlist :-
	nonvar(Compterm), !,
	subuniv(Compterm,0,Termlist).
Compterm =.. [F, .. Args] :- !,
	length(Args, Arity),
	functor(Compterm, F, Arity),
	subuniv(Compterm, 1, Args).
X =.. X :- atom(X).

subuniv(Compterm,Index, [Term, ..Resterms]) :- 
	term(Index, Compterm, Term), !,
	Index1 is Index + 1,
	subuniv(Compterm,Index1,Resterms).
subuniv(Compterm,Index,[]).

op(X, Y, []) :- !.
op(Precedence, Type, [A, ..B]) :- !,
	defop(Precedence, Type, A), 
	op(Precedence, Type, B).
op(Precedence, Type, Op) :- defop(Precedence, Type, Op).

op(700, fx, [trace, untrace])!

trace [] :- !.
trace [X, ..Y] :- !, spy X, trace Y.
trace X :- spy X.

untrace [] :- !.
untrace [X, ..Y] :- unspy X, untrace Y.
untrace X :- unspy X.

name(Atom, List) :-
	nonvar(List),
	concat(List, Atom).
name(Atom, List) :-
	atom(Atom),
	explode(Atom, List, 1).

explode(Atom, [A, ..B], N) :-
	char(N, Atom, A),
	!,
	(N1 is N + 1),
	explode(Atom, B, N1).
explode(Atom, [], _).

% findall(X, P, _) :- open_bag, P, write_bag(X).
% findall(_, _, L) :- close_bag(L).
% findall(_, _, _) :- free_bag, fail.

bagof(X, P, L) :-
	P,
	conc(L, X),
	fail.
bagof(_, _, []) :- !.
bagof(_, _, _).
bagof(_, _, L) :- free(L).

subgoal_of(X) :- ancestors([Y, ..Z]), member(X, Z).

member(X, [X, ..Y]).
member(X, [A, ..B]) :- member(X, B).

clause(Head, Body) :-
	functor(Head, Name, Arity),
	definition(Name, Defn),
	find_clause(Head, Defn, Body).

find_clause(Head, Defn, Body) :-
	head(Defn, Head),
	body(Defn, Body).
find_clause(Head, Defn, Body):-
	next_clause(Defn, Defn1),
	find_clause(Head, Defn1, Body).


retract((Head :- Body)) :- !,
	functor(Head, Name, Arity),
	definition(Name, Defn),
	remove_clause(Head, Defn, Body).
retract(Head) :-
	functor(Head, Name, Arity),
	definition(Name, Defn),
	remove_clause(Head, Defn, true).

remove_clause(Head, Defn, Body) :-
	head(Defn, Head),
	body(Defn, Body),
	unlink_clause(Defn).
remove_clause(Head, Defn, Body) :-
	match(Head, Defn, Body), !,
	next_clause(Defn, Defn1),
	remove_clause(Head, Defn1, Body).
remove_clause(Head, Defn, Body):-
	next_clause(Defn, Defn1),
	free(Defn),
	remove_clause(Head, Defn1, Body).

match(Head, Defn, Body) :-
	head(Defn, Head),
	body(Defn, Body), !,
	fail.
match(_, _, _).

retractall(X) :- retract((X :- Y)), fail.
retractall(_).

:- op(700, fx, [load, unload, em]).

unload Fname :-
	retract(file(Fname, Proc_list)), !,
	remove_all(Proc_list), !.
unload Fname.

remove_all([]) :- !.
remove_all([A, ..B]) :- free_proc(A), remove_all(B).

load Fname :- unload Fname, consult(Fname).

em Fname :- unload Fname, ef Fname, !, consult(Fname).

private([]) :- !.
private([A, ..B]) :- remob(A), private(B).

private([subuniv, exlode, member, free])!
private([find_clause, remove_clause, unlink_clause, match])!
private([open_bag, close_bag, write_bag, free_bag])!
private([remove_all, free_proc])!

ask(Q, A) :-
	prompt(Old, Q),
	ratom(A),
	prompt(_, Old).

%	help relies on the existence of the 'mc' multicolumn program.
%	If you have a Berkeley syste, ls will produce output in
%	multiple columns without the use of mc.

help :-
	print("For help please hang Jaakov Levvy").
help(S) :-
	concat([more, ' /usr/lib/prolog/help/', S], X),
	nl,
	system(X),
	nl.

fcomp([A|B]) :- !, compile(A), fcomp(B).
fcomp([]).

%Compatibility predicates from Malpas
%use this instead of builtin "name":
dec10name(Atom,IList) :-
    nonvar(IList),
    char__list(IList,CList),
    name(Atom,CList),!.

dec10name(Atom,IList) :-
   atom(Atom),
   name(Atom, CList),
   char__list(IList,CList),!.

get0(I) :- getc(C), ascii(C,I), !.
put(I) :- ascii(C,I), putc(C), !.

:- op(700, xfy, =<).
X =< Y :- X <= Y.
