Many prolog guides use the following definition of negation as failure.
% negation as failure
negation(G) :- call(G), !, fail.
negation(_).
Question: is it necessary to wrap G
in call/1
?
In the following definition, G
is written without wrapping it with a call/1
, and it seems to work.
% negation as failure
negation2(G) :- G, !, fail.
negation2(_).
Testing with swi-prolog (swish):
?- negation2(true)
false
?- negation2(false)
true
I also tested it with a short prolog program.
Question 2: Are there scenarios when we must write call(G)
and not simply G
?
First of all, these examples are about programs that go beyond first order logic, for you now permit variables to be in the place of goals. Inevitably, this transition will lead to some quirks on its way.
The common way to resolve this in ISO (and also in many systems that are not ISO like SWI) is to define an exact moment where first-order terms are converted into a goal or body of a clause (7.6.2). In this moment, a variable G_0
that occurs in the place of a goal is wrapped into call(G_0)
.
Thus, to answer Q1: No, it is not necessary to wrap that variable in your definition of negation/1
, since the term-to-body conversion is happening here at the time of the preparation for execution of this Prolog text.
So essentially there will never be a variable that is called directly. Instead, call/1
is used always.
Your question 2 thus boils down to: What is the difference between a non-variable term as a goal and that term just wrapped with call/1
?
?- false, call(1).
false.
?- false, 1.
error(type_error(callable,(false,1)),(',')/2).
?- G_0 = ( false, call(1)), G_0.
false.
?- G_0 = ( false, 1), G_0.
error(type_error(callable,(false,1)),(',')/2).
?- ( !, false ; true ).
false.
?- ( call(!), false ; true ).
true.
?- ( A = 1 -> B = 2 ; C = 3 ).
A = 1, B = 2.
?- ( ( A = 1 -> B = 2 ) ; C = 3 ).
A = 1, B = 2.
?- ( call(( A = 1 -> B = 2 )) ; C = 3 ).
A = 1, B = 2
; C = 3.
Note that in SWI, the toplevel has its own extra error checking which sometimes shows. With an extra indirection this can be circumvented. Here is such a case:
?- false, unknown.
false. % result in Scryer etc
?- false, unknown.
ERROR: Unknown procedure: unknown/0 (DWIM could not correct goal)
% SWI result only
?- G_0 = ( false, unknown ), G_0.
false. % same result everywhere