Guides teaching prolog are careful to dissuade students from thinking that predicates are functions.
After some thought, the idea that predicates are boolean functions seems valid.
Predicates have zero of finite input parameters, and their output is either true or false, success or fail.
Question: Is this dangerous to think of prolog predicates as boolean valued functions? What are the limitations of this analogy?
The following is the closest I have found to discussing this question meaningfully:
https://www.reddit.com/r/prolog/comments/f48grt/difference_between_predicate_and_function/
You can call predicates boolean functions, but look at this:
?- member(a, [a,b,c]).
true ;
false.
Also this:
?- member(X, [a,b,c]).
X = a ;
X = b ;
X = c.
Functions don't do that as far as I know. "Predicates" as used in procedural languages like C++ and Python are either true of false, once. They are not both true and false, nor are they true three times in a row.
EDIT: I can't tell which one is worse, reddit or stackoverflow. Both are terrible places to learn anything you didn't know already.
Related
Consider this Prolog program:
a(1).
b(X) :- X.
This is valid in SWI Prolog. And the following queries give desirable (at first glance) results without any warnings:
?- b(a(1)).
true
?- b(a(2)).
false
And then it is unclear for me, why this is allowed.
Fact a(1). says that predicate a/1 is true with argument 1.
Query b(a(1)) asks if predicate b/1 is true with a(1) function value. When this query is resolved, a(1) is checked as predicate, however it was taken from predicate argument context which should allow only terms there.
So different concepts are messed here. We have predicates which may be true or false depending on their arguments. And we have symbolic functions which are some abstract (symbolic) values defined by functor and arguments. The function does not necessary return true or false, it may be completely different domain. The only action with function here might be using it as a term in predicates to state some rules and facts about its value.
For me it looks like rule b(X) :- X. should not be compilable because variable X was firstly used in term context, and then in predicate context. Probably, variables should not be allowed at all in predicate context.
Isn't this some fundamental design inconsistency from math point of view?
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.
Suppose I have the knowledge base
likes(john,mary).
person(mary).
person(john).
If we ask prolog whether
|?- likes(mary,john)
It will answer no because we did not assert that. Is there any way to make prolog answer unknown unless we explicitly state.
\+ likes(mary,john)
In other words can we ask prolog to treat unbound expressions as possible rather than false. I've been using IDP system which permits existential quantification and treats non asserted relations as if unbound rather than false, but I would like to use something more mainstream.
http://adams.cs.kuleuven.be/idp/server.html
For example in IDP you can make the statement
vocabulary V{
type Person
Likes(Person,Person)
}
theory T: V{
//Everyone might like someone and disallow narcisiscm
!x : ?y: Likes(x,y) & ~Likes(x,x).
}
//some instance without special meaning
structure S:V{
Person={A..C}
}
procedure main(){
//Print all possible solutions
printmodels(allmodels(T,S))
}
Which yields
Number of models: 27
Model 1
=======
structure : V {
Person = { "A"; "B"; "C" }
Likes = { "A","B"; "A","C"; "B","A"; "B","C"; "C","A"; "C","B" }
}
//...
As stated, Prolog is using the closed-world assumption, i.e. asking if a fact is true means that we ask if we know it's true - a no means that we don't know if it's true, not that it's false. Of course, being a Turing-complete language you can simulate an open world - something like:
like(true, mary, john).
like(false, mary, nick).
like(unknown, X, Y).
Probably best to have some extra wrappers to deal with edge cases (e.g. having both true and false for a pair), and possibly use some higher-order predicate trick to avoid writing lots of boilerplate - but the core of the implementation is that you explicitly declare what's false, what's true and the rest is unknown.
What has been said so far is quite right: Prolog operates under the so-called Closed World Assumption (CWA). Still, I would like to offer a complementary perspective in addition to what has been posted already.
First, a Prolog program may not even terminate, and so we may never receive either of the possible answers you mention.
But even if the program does terminate, we may still obtain answers that are neither equivalent to true nor to false.
For example, using GNU Prolog:
| ?- X #\= 3.
X = _#2(0..2:4..127#)
Here, the answer is a pending constraint, a goal that is said to flounder because its truth is not definitely decided.
Such answers may or may not describe solutions.
For example:
| ?- fd_all_different([X,Y,Z]), fd_domain([X,Y,Z], 0, 1).
X = _#2(0..1)
Y = _#20(0..1)
Z = _#50(0..1)
yes
In this case, no solutions exist! To see this, we need to explicitly search for them:
| ?- fd_all_different([X,Y,Z]), fd_domain([X,Y,Z], 0, 1),
fd_labeling([X,Y,Z]).
no
Thus, in the example above, it may really be more advisable to answer with maybe instead of yes.
Moreover, we know from fundamental logical theorems that such issues are unavoidable when reasoning over integers.
In this sense, Prolog systems can really give answers whose truth not only isn't, but moreover cannot be determined.
The question is : The salt has been stolen! Well, it was found that the culprit was either the Caterpillar,
Bill the Lizard or the Cheshire Cat. The three were tried and made the following
statements in court:
CATERPILLAR: Bill the Lizard ate the salt.
BILL THE LIZARD: That is true!
CHESHIRE CAT: I never ate the salt.
As it happened, at least one of them lied and at least one told the truth. Who ate the
salt?
I know for sure if bill is true, than all statements are true, and if cheshire is true, then all are false, so it must be the caterpillar.
Looking at in predicate calculus and programming it, it would be something like this right:
suspect(caterpillar).
suspect(lizard).
suspect(cat).
:- suspect(cat), suspect(lizard).
:- suspect(cat), suspect(caterpillar).
:- suspect(lizard), suspect(caterpillar).
%where these imply not more than one of these can be true or returned in our set
But then further describing this in predicate logic I don't how I would describe the descriptions or plea's they have made. And how that if one statement is true can imply that others may be falses.
One nice thing about this puzzle is that you do not even need first-order predicate logic to model it: It suffices to use propositional logic, because whether a suspect lies or tells the truth can be indicated with a Boolean variable, and the statements themselves are also only statements over Boolean variables.
Thus, consider using a constraint solver over Boolean variables when solving this task with Prolog. See clpb for more information about this.
Here is a sample solution, using SICStus Prolog or SWI:
:- use_module(library(clpb)).
solution(Pairs) :-
Suspects = [_Caterpillar,Lizard,Cat],
pairs_keys_values(Pairs, [caterpillar,lizard,cat], Suspects),
Truths = [CaterpillarTrue,LizardTrue,CatTrue],
% exactly one of them ate the salt
sat(card([1], Suspects)),
% the statements
sat(CaterpillarTrue =:= Lizard),
sat(LizardTrue =:= Lizard),
sat(CatTrue =:= ~Cat),
% at least one of them tells the truth:
sat(card([1,2,3], Truths)),
% at least one of them lies:
sat(card([1,2,3], [~CaterpillarTrue,~LizardTrue,~CatTrue])).
And from this the unique solution is readily determined without search:
?- solution(Pairs).
Pairs = [caterpillar-1, lizard-0, cat-0].
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.