Prolog library: not.pl
pereira at sri-unix.UUCP
pereira at sri-unix.UUCP
Mon Aug 15 15:56:07 AEST 1983
% File : NOT.PL
% Author : R.A.O'Keefe
% Updated: 21 May 1983
% Purpose: "suspicious" negation and double negation
/* This file defines a version of 'not' which checks that there are
no free variables in the goal it is given to "disprove". Bound
variables introduced by the existential quantifier ^ or set/bag
dummy variables are accepted. If any free variables are found,
a message is printed on the terminal and a break level entered.
It is intended purely as a debugging aid, though it shouldn't slow
interpreted code down much. There are several other debugging
aids that you might want to use as well, particularly
unknown(_, trace)
which will detect calls to undefined predicates (as opposed to
predicates which ahve clauses that don't happen to match).
*/
:- public
not/1. % new checking denial
:- mode
explicit_binding(+,+,-,-),
free_variables(+,+,+,-),
free_variables(+,+,+,+,-),
list_is_free_of(+,+),
not(+),
note_free_variable(+,+,+,-),
term_is_free_of(+,+),
term_is_free_of(+,+,+).
not(Goal) :-
free_variables(Goal, [], [], Vars),
Vars \== [], !,
telling(Old), tell(user),
nl, write('** '), write(not(Goal)),
nl, write('-- free variables '), write(Vars),
nl, trace, break,
tell(Old), !,
call(Goal),
!, fail.
not(Goal) :-
call(Goal),
!, fail.
not(_).
% In order to handle variables properly, we have to find all the
% universally quantified variables in the Filter. Any variables
% that are left are universally quantified, unless
% a) they occur in the template
% b) they are bound by X^P, setof, or bagof
% free_variables(Filter, Template, OldList, NewList)
% finds this set, using OldList as an accumulator.
free_variables(Term, Bound, OldList, NewList) :-
var(Term), !,
note_free_variable(Term, Bound, OldList, NewList).
free_variables(Term, Bound, OldList, NewList) :-
explicit_binding(Term, Bound, NewTerm, NewBound), !,
free_variables(NewTerm, NewBound, OldList, NewList).
free_variables(Term, Bound, OldList, NewList) :-
functor(Term, _, N),
free_variables(N, Term, Bound, OldList, NewList).
free_variables(0, Term, Bound, AnsList, AnsList) :- !.
free_variables(N, Term, Bound, OldList, NewList) :-
arg(N, Term, Argument),
free_variables(Argument, Bound, OldList, MidList),
M is N-1, !,
free_variables(M, Term, Bound, MidList, NewList).
% explicit_binding checks for goals known to existentially quantify
% one or more variables. In particular \+ is quite common.
explicit_binding(\+ Test, Bound, fail, Bound ) :- !.
explicit_binding(not(Test), Bound, fail, Bound ) :- !.
explicit_binding(Var^Test, Bound, Test, [Var|Bound]) :- !.
explicit_binding(setof(Var,Test,Set), Bound, (Test,Set), [Var|Bound]) :- !.
explicit_binding(bagof(Var,Test,Set), Bound, (Test,Set), [Var|Bound]) :- !.
% note_free_variable(Var, Bound, OldList, NewList)
% checks a variable Var. If the variable is existentially bound (i.e.
% it occurs in Bound) or already known, no change is made, otherwise
% it is added to the NewList.
note_free_variable(Var, Bound, List, [Var|List]) :-
term_is_free_of(Bound, Var),
list_is_free_of(List, Var), !.
note_free_variable(_, _, List, List).
term_is_free_of(Term, Var) :-
var(Term), !,
Term \== Var.
term_is_free_of(Term, Var) :-
functor(Term, _, N),
term_is_free_of(N, Term, Var).
term_is_free_of(0, Term, Var) :- !.
term_is_free_of(N, Term, Var) :-
arg(N, Term, Argument),
term_is_free_of(Argument, Var),
M is N-1, !,
term_is_free_of(M, Term, Var).
list_is_free_of([Head|Tail], Var) :- !,
Head \== Var, !,
list_is_free_of(Tail, Var).
list_is_free_of([], _).
More information about the Comp.sources.unix
mailing list