I started to learn Prolog following the book Programming in Prolog: Using the ISO Standard. At page 7 of the intro to the language they made the assertion : "In Prolog the answer no is used to mean nothing unifies with the question. It is important to remember that no is not the same as false". So why SWI-Prolog uses the falseand truestatement instead of yesor no?
To begin with, the ISO standard (ISO/IEC 13211-1:1995) does not define
a toplevel loop. In 1 Scope it reads:
NOTE — This part of ISO/IEC 13211 does not specify:
...
f) the user environment (top level loop, debugger, librarysystem, editor, compiler etc.) of a Prolog processor.
Traditionally, the answer of a query has been answered with yes or no. In case of yes, answer substitutions were shown, if present.
Today, with more and more constraints present in answers, the traditional toplevel loop becomes a bit cumbersome to use. What is the correct answer to
?- dif(X,a).? It cannot be a yes, it might be a maybe,which was used first by Jaffar et al.s CLP(R). But very frequently one wants to reuse the answer.
?- dif(X,a).
dif(X,a).
?- dif(b,a).
true.
?- true.
true.
Following Prolog IV's pioneering toplevel, the idea in SWI is to produce text as an answer such that you can paste it back to get the very same result. In this manner the syntax of answers is specified to some degree - it has to be valid Prolog text.
So if there is no longer yes, why should there be no? For this reason SWI gives false. as an answer. Prior to SWI, Prolog IV did respond false. Note for example the following fixpoint in SWI:
?- true ; false.
true
; false.
So even this tiny detail is retained in answers. Whereas in Prolog IV this is collapsed into true because Prolog IV shows all answers in one fell swoop.
?- true ; false.
true.
For more on answers, see this.
I came across this question recently and took a look at an old (third) edition of Clocksin and Mellish which discusses the difference between yes, no and true, false. From my reading of the text this is what I understand:
yes and no are returned after Edinburgh Prolog evaluates a query using its 'database' of facts and rules. yes means the result is provable from the facts and rules in the database; no means it's not provable from those rules and facts.
true and false refer to the real world. It's possible for Prolog to return no to the query isAmerican(obama) simply because this fact is not in the database; whereas in fact (in the real world) Obama is an American and so this fact is true in reality.
Edinburgh Prolog returns yes and no to queries, however later implementations, like SWI Prolog, return true and false. Clearly later implementors didn't consider this distinction very important, but in fact it is a crucial distinction. When Edinburgh Prolog returns a no then it means "not provable from the database"; and when SWI Prolog returns false it also means "not provable from the database". They mean the same thing (semantically) but they look different (syntactically) because SWI Prolog doesn't conform entirely to Edinburgh Prolog conventions.
Related
In many Prolog guides the following code is used to illustrate "negation by failure" in Prolog.
not(Goal) :- call(Goal), !, fail.
not(Goal).
However, those same tutorials and texts warn that this is not "logical negation".
Question: What is the difference?
I have tried to read those texts further, but they don't elaborate on the difference.
I like #TesselatingHeckler's answer because it puts the finger on the heart of the matter. You might still be wondering, what that means for Prolog in more concrete terms. Consider a simple predicate definition:
p(something).
On ground terms, we get the expected answers to our queries:
?- p(something).
true.
?- \+ p(something).
false.
?- p(nothing).
false.
?- \+ p(nothing).
true.
The problems start, when variables and substitution come into play:
?- \+ p(X).
false.
p(X) is not always false because p(something) is true. So far so good. Let's use equality to express substitution and check if we can derive \+ p(nothing) that way:
?- X = nothing, \+ p(X).
X = nothing.
In logic, the order of goals does not matter. But when we want to derive a reordered version, it fails:
?- \+ p(X), X = nothing.
false.
The difference to X = nothing, \+ p(X) is that when we reach the negation there, we have already unified X such that Prolog tries to derive \+p(nothing) which we know is true. But in the other order the first goal is the more general \+ p(X) which we saw was false, letting the whole query fail.
This should certainly not happen - in the worst case we would expect non-termination but never failure instead of success.
As a consequence, we cannot rely on our logical interpretation of a clause anymore but have to take Prolog's execution strategy into account as soon as negation is involved.
Logical claim: "There is a black swan".
Prolog claim: "I found a black swan".
That's a strong claim.
Logical negation: "There isn't a black swan".
Prolog negation: "I haven't found a black swan".
Not such a strong a claim; the logical version has no room for black swans, the Prolog version does have room: bugs in the code, poor quality code not searching everywhere, finite resource limits to searching the entire universe down to swan size areas.
The logical negation doesn't need anyone to look anywhere, the claim stands alone separate from any proof or disproof. The Prolog logic is tangled up in what Prolog can and cannot prove using the code you write.
There are a couple of reasons why,
Insufficient instantiation
A goal not(Goal_0) will fail, iff Goal0 succeeds at the point in time when this not/1 is executed. Thus, its meaning depends on the very instantiations that happen to be present when this goal is executed. Changing the order of goals may thus change the outcome of not/1. So conjunction is not commutative.
Sometimes this problem can be solved by reformulating the actual query.
Another way to prevent incorrect answers is to check if the goal is sufficiently instantiated, by checking that say ground(Goal_0) is true producing an instantiation error otherwise. The downside of this approach is that quite too often instantiation errors are produced and people do not like them.
And even another way is to delay the execution of Goal_0 appropriately. The techniques to improve the granularity of this approach are called constructive negation. You find quite some publications about it but they have not found their way into general Prolog libraries. One reason is that such programs are particularly hard to debug when many delayed goals are present.
Things get even worse when combining Prolog's negation with constraints. Think of X#>Y,Y#>X which does not have a solution but not/1 just sees its success (even if that success is conditional).
Semantic ambiguity
With general negation, Prolog's view that there exists exactly one minimal model no longer holds. This is not a problem as long as only stratified programs are considered. But there are many programs that are not stratified yet still correct, like a meta-interpreter that implements negation. In the general case there are several minimal models. Solving this goes far beyond Prolog.
When learning Prolog stick to the pure, monotonic part first. This part is much richer than many expect. And you need to master that part in any case.
I'm working through Clocksin and Mellish to try and finally go beyond just dabbling in Prolog. FWIW, I'm running SWI-Prolog:
SWI-Prolog version 7.2.3 for x86_64-linux
Anyway, I implemented a diff/2 predicate as part of exercise 1.4. The predicate is very simple:
diff(X,Y) :- X \== Y.
And it works when used in the sister_of predicate, like this:
sister_of(X,Y) :-
female(X),
diff(X,Y),
parents(X, Mum, Dad ),
parents(Y, Mum, Dad ).
in that, assuming the necessary additional facts, doing this:
?- sister_of(alice,alice).
returns false as expected. But here's the rub. If I do this instead:
?- sister_of(alice, Who).
(again, given the additional facts necessary)
I get
Who = edward ;
Who = alice;
false
Even though, as already shown, the sister_of predicate does not treat alice as her own sister.
On the other hand, if I use the SWI provided dif/2 predicate, then everything works the way I would naively expect.
Can anyone explain why this is happening this way, and why my diff implementation doesn't work the way I'm expecting, in the case where I ask for additional unifications from that query?
The entire source file I'm working with can be found here
Any help is much appreciated.
As you note, the problem stems from the interplay between equality (or rather, inequality) and unification. Observe that in your definition of sister_of, you first find a candidate value for X, then try to constrain Y to be different, but Y is still an uninstantiated logic variable and the check is always going to succeed, like diff(alice, Y) will. The following constraints, including the last one that gives a concrete value to Y, come too late.
In general, what you need to do is ensure that by the time you get to the inequality check all variables are instantiated. Negation is a non-logical feature of Prolog and therefore potentially dangerous, but checking whether two ground terms are not equal is safe.
I'm studying for an Artificial Intelligence exam and struggling to understand how to answer certain questions focusing on Predicates. The two questions in particular are:
Define a predicate which behaves as follows -
?- stage_name(billie, Name).
Name = rose
yes
?- stage_name(jenna,Name).
Name = clara
yes
Write a predicate that takes two argument and is true if both actors are on the same show. Thus
?-same_show(david,clara).
is true, whilst
?-same_continent(elisabeth,skippy).
is not
I don't really understand how I would answer these questions, and I'm finding very little Prolog information online. I would appreciate some help. Apologies for the formatting.
1:
stage_name(billie,rose).
stage_name(jenna,Name) :- Name=clara.
Explanation:
Given a query, Prolog looks for an appropriate predicate according to the input parameters and the name and "executes" it. The result is either true/false if no output parameter is given. In this case there is one (Name) which can be seen from the leading capital letter. Note that there are two possible ways to implement this. The former is probably the most common (predicates of this form are called "facts" whereas predicates such as the lower are called "rules").
2:
As mentioned in my comment, I don't really understand the connection between the two given predicates. Also it feels like there is something missing such as a facts that determine which person is on which show...
Assuming such facts are missing, I would write the Prolog program as follows:
onShow(david, s1).
onShow(clara, s1).
onShow(bernie, s2).
same_show(P1, P2) :- onShow(P1,X), onShow(P2,X).
Explanation:
The predicate is only true if both P1 and P2 visit the same show X.
Hints:
A "comma" represents a logical AND operator. Having different rules with the same name and parameter count represents logical OR. Edit: As Boris mentioned in a comment, this is not exactly true. This association simply helped me to understand the connection between "Logical Predicates" and "Prolog Predicates".
Visit SWISH to test your Prolog programs.
The matter of deterministic success of some Prolog goal has turned up time and again in—at least—the following questions:
Reification of term equality/inequality
Intersection and union of 2 lists
Remove duplicates in list (Prolog)
Prolog: How can I implement the sum of squares of two largest numbers out of three?
Ordering lists with constraint logic programming)
Different methods were used (e.g., provoking certain resource errors, or looking closely at the exact answers given by the Prolog toplevel), but they all appear somewhat ad-hack to me.
I'm looking for a generic, portable, and ISO-conformant way to find out if the execution of some Prolog goal (which succeeded) left some choice-point(s) behind. Some meta predicate, maybe?
Could you please hint me in the right direction? Thank you in advance!
Good news everyone: setup_call_cleanup/3 (currently a draft proposal for ISO) lets you do that in a quite portable and beautiful way.
See the example:
setup_call_cleanup(true, (X=1;X=2), Det=yes)
succeeds with Det == yes when there are no more choice points left.
EDIT: Let me illustrate the awesomeness of this construct, or rather of the very closely related predicate call_cleanup/2, with a simple example:
In the excellent CLP(B) documentation of SICStus Prolog, we find in the description of labeling/1 a very strong guarantee:
Enumerates all solutions by backtracking, but creates choicepoints only if necessary.
This is really a strong guarantee, and at first it may be hard to believe that it always holds. Luckily for us, it is extremely easy to formulate and generate systematic test cases in Prolog to verify such properties, in essence using the Prolog system to test itself.
We start with systematically describing what a Boolean expression looks like in CLP(B):
:- use_module(library(clpb)).
:- use_module(library(lists)).
sat(_) --> [].
sat(a) --> [].
sat(~_) --> [].
sat(X+Y) --> [_], sat(X), sat(Y).
sat(X#Y) --> [_], sat(X), sat(Y).
There are in fact many more cases, but let us restrict ourselves to the above subset of CLP(B) expressions for now.
Why am I using a DCG for this? Because it lets me conveniently describe (a subset of) all Boolean expressions of specific depth, and thus fairly enumerate them all. For example:
?- length(Ls, _), phrase(sat(Sat), Ls).
Ls = [] ;
Ls = [],
Sat = a ;
Ls = [],
Sat = ~_G475 ;
Ls = [_G475],
Sat = _G478+_G479 .
Thus, I am using the DCG only to denote how many available "tokens" have already been consumed when generating expressions, limiting the total depth of the resulting expressions.
Next, we need a small auxiliary predicate labeling_nondet/1, which acts exactly as labeling/1, but is only true if a choice-point still remains. This is where call_cleanup/2 comes in:
labeling_nondet(Vs) :-
dif(Det, true),
call_cleanup(labeling(Vs), Det=true).
Our test case (and by this, we actually mean an infinite sequence of small test cases, which we can very conveniently describe with Prolog) now aims to verify the above property, i.e.:
If there is a choice-point, then there is a further solution.
In other words:
The set of solutions of labeling_nondet/1 is a proper subset of that of labeling/1.
Let us thus describe what a counterexample of the above property looks like:
counterexample(Sat) :-
length(Ls, _),
phrase(sat(Sat), Ls),
term_variables(Sat, Vs),
sat(Sat),
setof(Vs, labeling_nondet(Vs), Sols),
setof(Vs, labeling(Vs), Sols).
And now we use this executable specification in order to find such a counterexample. If the solver works as documented, then we will never find a counterexample. But in this case, we immediately get:
| ?- counterexample(Sat).
Sat = a+ ~_A,
sat(_A=:=_B*a) ? ;
So in fact the property does not hold. Broken down to the essence, although no more solutions remain in the following query, Det is not unified with true:
| ?- sat(a + ~X), call_cleanup(labeling([X]), Det=true).
X = 0 ? ;
no
In SWI-Prolog, the superfluous choice-point is obvious:
?- sat(a + ~X), labeling([X]).
X = 0 ;
false.
I am not giving this example to criticize the behaviour of either SICStus Prolog or SWI: Nobody really cares whether or not a superfluous choice-point is left in labeling/1, least of all in an artificial example that involves universally quantified variables (which is atypical for tasks in which one uses labeling/1).
I am giving this example to show how nicely and conveniently guarantees that are documented and intended can be tested with such powerful inspection predicates...
... assuming that implementors are interested to standardize their efforts, so that these predicates actually work the same way across different implementations! The attentive reader will have noticed that the search for counterexamples produces quite different results when used in SWI-Prolog.
In an unexpected turn of events, the above test case has found a discrepancy in the call_cleanup/2 implementations of SWI-Prolog and SICStus. In SWI-Prolog (7.3.11):
?- dif(Det, true), call_cleanup(true, Det=true).
dif(Det, true).
?- call_cleanup(true, Det=true), dif(Det, true).
false.
whereas both queries fail in SICStus Prolog (4.3.2).
This is the quite typical case: Once you are interested in testing a specific property, you find many obstacles that are in the way of testing the actual property.
In the ISO draft proposal, we see:
Failure of [the cleanup goal] is ignored.
In the SICStus documentation of call_cleanup/2, we see:
Cleanup succeeds determinately after performing some side-effect; otherwise, unexpected behavior may result.
And in the SWI variant, we see:
Success or failure of Cleanup is ignored
Thus, for portability, we should actually write labeling_nondet/1 as:
labeling_nondet(Vs) :-
call_cleanup(labeling(Vs), Det=true),
dif(Det, true).
There is no guarantee in setup_call_cleanup/3 that it detects determinism, i.e. missing choice points in the success of a goal. The 7.8.11.1 Description draft proposal only says:
c) The cleanup handler is called exactly once; no later than
upon failure of G. Earlier moments are:
If G is true or false, C is called at an implementation
dependent moment after the last solution and after the last
observable effect of G.
So there is currently no requirement that:
setup_call_cleanup(true, true, Det=true)
Returns Det=true in the first place. This is also reflected in the test cases 7.8.11.4 Examples that the draf proposal gives, we find one test case which says:
setup_call_cleanup(true, true, X = 2).
Either: Succeeds, unifying X = 2.
Or: Succeeds.
So its both a valid implementation, to detect determinism and not to detect determinism.
I've just started learning Prolog and I encountered a problem that I don't understand.
When I ask:
?- fail; true.
Prolog answers:
true
Which is something I expected. But, if I ask:
?- true; fail.
Prolog answers:
true ;
false.
..and I don't understand why. The disjunction operator should be commutative. Why are these two Prolog answers different?
Also note that the Prolog disjunction operator, (;)/2, is not commutative in general. For example:
?- !; write(else).
true.
?- write(then); !.
then
true ;
true.
The right branch of the disjunction is only tried on backtracking if the implicit choice point is not cut when executing the left branch. Note that a clause such as:
foo :- (!; write(else)).
is equivalent to:
foo :- !.
foo :- write(else).
Thus, cuts and (other) side-effects result in (;)/2 not behaving as logical disjunction.
it's just a detail of top level interaction, then you could observe a different behaviour depending on Prolog interpreter you're using.
SWI-Prolog, in introductory documentation, gives some information:
2.1.2 Executing a query
After loading a program, one can ask Prolog queries about the program. The query below asks Prolog what food `sam' likes. The system responds with X = if it can prove the goal for a certain X. The user can type the semi-colon (;) or spacebar6 if (s)he wants another solution. Use the return key if you do not want to see the more answers. Prolog completes the output with a full stop (.) if the user uses the return key or Prolog knows there are no more answers. If Prolog cannot find (more) answers, it writes false.
The confusion regards how prolog displays results. When you make a query in prolog, it will attempt to find all possible answers. That means it will start at the first fact or clause, go through them sequentially and, when it can finally make the query true, displays the answer. If there was a choice point in the process of finding the last solution, prolog prompts the user to seek more possible successful solutions.
In the case of:
?- false ; true.
This query starts by looking at the clause false, which fails and then, since there's a disjunction ;, checks the clause after the ; which is true. This succeeds, and prolog displays:
true
Note that when it found this solution, there were no more choices, so there's no prompt for further solutions.
Now let's look at the second example:
?- true ; false.
Prolog looks at the first clause, true, and succeeds and tells the user:
true
But in this case, it hasn't exhausted all of the possible solutions since there's a disjunction ; that created another choice. So when you enter the ; at the prompt:
true ;
You tell prolog to find more solutions. Prolog goes back and checks the clause after the disjunction and encounters false. This fails and there are no other solutions. Therefore, your request for further solutions fails and prolog outputs false:
true ;
false
The first true means it succeeded. The false means it found no more solutions and failed on the second attempt.
Prolog's behavior is to seek solutions sequentially through the appropriate clauses and present them as long as you ask for them until it fails. When it finally fails, you get false. Some prologs output no. The behavior above is not a commutativity issue.