:- module(_,_).

% Meta-calls and cut: Negation as failure
% ---------------------------------------

not( Goal) :- call(Goal), !, fail.
not(_Goal).
% This is available from the library as \+/1

% Try:
% ?- not( member(c, [a, k, l]) ).
% ?- \+ member(c, [a, k, l]).

% Another example: 
% ----------------
    
unmarried_student(X) :- 
    \+ married(X),
    student(X).

student(joe).
married(john).

% Note that:
% Joe is an unmarried student
% John is NOT an unmarried student!

% Try:
% ?- unmarried_student(joe).
% ?- unmarried_student(john).
% ?- unmarried_student(X).
% This last one is wrong, an unmarried student does exist!

% Observation: not/1 is correct if the argument is ground (is a term
% that does not contain variables). 
% ground/1 is available:

% Try:
% ?- ground(unmarried_student(joe)).
% ?- ground(unmarried_student(X)).

% Better (safer) implementation of negation: 
not_(G) :-
    ground(G), !,
    \+ G. 
not_(G) :-
    write('ERROR: Non-ground goal in negation: '), write(G), nl,
    abort.

unmarried_student_with_check(X) :- 
    not_(married(X)), 
    student(X).

% Try:
% ?- unmarried_student_with_check(joe).
% ?- unmarried_student_with_check(john).
% ?- unmarried_student_with_check(X).

% Alternative implementation using an assertion.
% We load assertions package and run-time checking of assertions:
:- use_package([assertions,modes,rtchecks]).

:- pred not__(G) : ground(G).
not__(G) :- \+ G.

assrt_unmarried_student(X) :- 
    not__(married(X)), 
    student(X).

% Try:
% ?- assrt_unmarried_student(joe).
% ?- assrt_unmarried_student(X).

% Another example: overlap/2 and disjoint/2
overlap(S1,S2) :-  % S1 and S2 overlap if they share an element
    member(X,S1), member(X,S2).

disjoint(S1,S2) :- \+ overlap(S1,S2).

% Try:
% ?- disjoint([1,2,3,4],[a,b,c]).
% ?- disjoint([1,2,3,4],[2,4,c]).

% Another example of meta-call + cut:
% once(G): only one solution of G
once(X) :- call(X), !.

% Try (asking for more alternatives):
% ?- member(X,[1,2,3]).
% ?- once(member(X,[1,2,3])).
