I am working through Seven Languages in Seven Weeks, but there is something I don't understand about prolog. I have the following program (based on their wallace and grommit program):
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- \+(X = Y), onTeam(X, Z), onTeam(Y, Z).
and load it like this
?- ['teams.pl'].
true.
but it doesn't give me any solutions to the following
?- teamMate(a, X).
false.
it can solve simpler stuff (which is shown in the book):
?- onTeam(b, X).
X = aTeam ;
X = superTeam.
and there are solutions:
?- teamMate(a, b).
true ;
false.
What am I missing? I have tried with both gnu prolog and swipl.
...AND THERE IS MORE...
when you move the "can't be your own teammate" restriction to then end:
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- onTeam(X, Z), onTeam(Y, Z), \+(X = Y).
it gives me the solutions I would expect:
?- ['teams.pl'].
true.
?- teamMate(a, X).
X = b.
?- teamMate(b, X).
X = a ;
X = c.
What gives?
You have made a very good observation! In fact, the situation is even worse, because even the most general query fails:
?- teamMate(X, Y).
false.
Declaratively, this means "there are no solutions whatsoever", which is obviously wrong and not how we expect relations to behave: If there are solutions, then more general queries must not fail.
The reason you get this strange and logically incorrect behaviour is that (\+)/1 is only sound if its arguments are sufficiently instantiated.
To express disequality of terms in a more general way, which works correctly no matter if the arguments are instantiated or not, use dif/2, or, if your Prolog system does not provide it, the safe approximation iso_dif/2 which you can find in the prolog-dif tag.
For example, in your case (note_that_I_am_using_underscores_for_readability instead of tuckingTheNamesTogetherWhichMakesThemHarderToRead):
team_mate(X, Y) :- dif(X, Y), on_team(X, Z), on_team(Y, Z).
Your query now works exactly as expected:
?- team_mate(a, X).
X = b.
The most general query of course also works correctly:
?- team_mate(X, Y).
X = a,
Y = b ;
X = b,
Y = a ;
X = b,
Y = c ;
etc.
Thus, using dif/2 to express disequality preserves logical-purity of your relations: The system now no longer simply says false even though there are solutions. Instead, you get the answer you expect! Note that, in contrast to before, this also works no matter where you place the call!
The answer by mat gives you some high-level considerations and a solution. My answer is a more about the underlying reasons, which might or might not be interesting to you.
(By the way, while learning Prolog, I asked pretty much the same question and got a very similar answer by the same user. Great.)
The proof tree
You have a question:
Are two players team mates?
To get an answer from Prolog, you formulate a query:
?- team_mate(X, Y).
where both X and Y can be free variables or bound.
Based on your database of predicates (facts and rules), Prolog tries to find a proof and gives you solutions. Prolog searches for a proof by doing a depth-first traversal of a proof tree.
In your first implementation, \+ (X = Y) comes before anything else, so it at the root node of the tree, and will be evaluated before the following goals. And if either X or Y is a free variable, X = Y must succeed, which means that \+ (X = Y) must fail. So the query must fail.
On the other hand, if either X or Y is a free variable, dif(X, Y) will succeed, but a later attempt to unify them with each other must fail. At that point, Prolog will have to look for a proof down another branch of the proof tree, if there are any left.
(With the proof tree in mind, try to figure out a way of implementing dif/2: do you think it is possible without either a) adding some kind of state to the arguments of dif/2 or b) changing the resolution strategy?)
And finally, if you put \+ (X = Y) at the very end, and take care that both X and Y are ground by the time it is evaluated, then the unification becomes more like a simple comparison, and it can fail, so that the negation can succeed.
Related
I'm trying to understand what assert and retract do with the term they are passed. If I run the following:
?- assertz(item(first)).
true.
?- assertz(item(second)).
true.
?- assertz((item(Y) :- =(Y, third), writeln(Y))).
true.
?- retract(item(X)).
X = first ;
X = second ;
false.
retract/1 removes all of the items but my writeln/1 is never called, so it appears retract is not actually resolving the term it is passed. It looks like it is doing some special operation where it:
Unifies the term with only facts (i.e. rules with no tail) in the database
Retracts each one after applying the substitution from unification
Is this right? Or is something else happening here?
Said another way: If I write my own single argument rule, Prolog does not automatically unify item(X) with the database and iterate through all facts that are item/1. It just gives me item(X). How is retract doing its magic?
?- assertz((myRule(X) :- writeln(X))).
true.
? myRule(item(X)).
item(_2556)
true.
Answer with further clarification:
Based on the answer by User9213, it appears that the answer is "retract (but not assert!) has a funny behavior where it does a simple unification of its term before it does something to the database". I'm left wondering why other built-in functions that I've seen (like atom/1 and writeln/1) don't appear to do this. Maybe it is more common than I've experienced?
For consistency, it seems like retract should have required ground terms and if the user wanted to do something like my above example, they could have done this:
?- (item(X), retract(item(X))).
It all makes me think I'm missing something or maybe these built in functions were just inconsistently designed? Any clarification that would explain that would be great.
To add my voice to the chorus, yes, all these predicates (assert*, retract*) manipulate the Prolog database of facts and rules; they do not evaluate their arguments as if they were facts or rules. Yes, they just do "syntactic" unification between their argument and the facts and rules in the database.
Prolog is a homoiconic language. The program can be manipulated as if it was data; the data structures can be interpreted as if they were the program. Most importantly: whether a certain structure is data or program depends only on the context.
You seem to understand this, but for the next poor soul that stumbles across your question and this answer, here is a toy example to demonstrate.
There is a built-in predicate atom/1 that succeeds if its argument is, well, an atom:
?- atom(foo).
true.
?- atom(Bar). % Bar is a free variable, which is not an atom
false.
?- atom(atom(bar)). % atom(bar) is a compound term, which is not an atom
false.
But atom(bar) is just a compound term in the last query. It is a compound term with a functor atom/1. Its only argument is an atom. So if you now queried it:
?- atom(bar).
true.
There is also this really nice predicate called call. It makes it even easier to blur the lines between program and data. The following three queries are identical in meaning:
?- atom(bar).
true.
?- call(atom, bar).
true.
?- call(atom(bar)).
true.
In addition, you can dynamically (at run-time) create a data structure and evaluate it as program. Here is a naive implementation of call/2 that can evaluate predicates, provided a predicate name and a list of arguments. It constructs the compound term using "univ" and evaluates it by just placing it in a slot where a subgoal is supposed to be. I'll call it my_call/2 and I will add it to the database using assertz:
?- assertz((my_call(Name, Args) :- Goal =.. [Name|Args], Goal)).
true.
?- my_call(between, [1, 3, X]).
X = 1 ;
X = 2 ;
X = 3.
Do you see what is going on? (Note: it seems that call is a relatively new addition to Prolog. Before call was widely available, you had to do this trick if you wanted to meta-call predicates. I don't know this from experience, just educated guessing based on things I've read or heard and can't be bothered to cite right now.)
So, let's try that again. In reality things are more complicated, but very simplified:
A Prolog program is a set of predicates. Not ordered!
Each predicate is a list of clauses. It is a list because a predicate may have 0 or more clauses, and they have order.
A clause can be a fact or a rule.
A rule is a compound term with functor :-/2. Yes, this is right. To see what I mean:
?- assertz(:-(foo(X), between(1, 3, X))).
true.
?- listing(foo/1).
:- dynamic foo/1.
foo(A) :-
between(1, 3, A).
true.
This is just another way to write it. It is more conventional.
So indeed, these two are very different:
foo(X). % a fact
foo(X) :- between(1, 3, X). % a rule
You cannot unify the one with the other. This is why, if you want to retract foo(X) :- between(1, 3, X), you cannot just pass foo(X) as the argument to retract. Or, to complete your example:
?- assertz(item(first)).
true.
?- assertz(item(second)).
true.
?- assertz((item(Y) :- =(Y, third), writeln(Y))).
true.
?- retract(item(X)).
X = first ;
X = second ;
false.
?- retract((item(X) :- X = Y, writeln(X))).
Y = third.
Do you see it now?
I had a vague memory of there being a retractall/1 that lives alongside retract/1 and it turns out the reason for it is situations like this. retract/1 accepts a Prolog term, as the documentation states:
retract(+Term)
When Term is an atom or a term it is unified with the first unifying fact or clause in the database. The fact or clause is removed from the database.
Emphasis added by me.
This is illustrated by the following:
?- asserta(foo(X) :- X = 2 ; X = 4).
true.
?- foo(X).
X = 2 ;
X = 4.
?- retract(foo(X)).
false.
?- foo(X).
X = 2 ;
X = 4.
?- retract(foo(X) :- X = 2 ; X = 4).
true.
?- foo(X).
false.
Note that if you furnish the complete clause you gave to asserta/1, it will be retracted. As #CapelliC points out below, you can also furnish a clause with a variable as a parameter to retract things with bodies:
retract(foo(X) :- Y).
However, if you do want to retract things that match a pattern, you can use retractall/1, which the documentation states:
retractall(+Head)
All facts or clauses in the database for which the head unifies with Head are removed.
This is illustrated by the following:
?- asserta(foo(X) :- X = 2 ; X = 4).
true.
?- foo(X).
X = 2 ;
X = 4.
?- retractall(foo(X)).
true.
?- foo(X).
false.
Another important difference between these two is that retract/1 will remove one thing at a time, and it will unify those things:
?- asserta(foo(X) :- X = 2).
true.
?- asserta(foo(X) :- X = 4).
true.
?- retract(foo(X) :- Y).
Y = (X=4) ;
Y = (X=2) .
This is in contrast to retractall/1 which will remove everything that matches the pattern, without unifying anything:
?- asserta(foo(X) :- X=2).
true.
?- asserta(foo(X) :- X=4).
true.
?- foo(X).
X = 4 ;
X = 2.
?- retractall(foo(X)).
true.
?- foo(X).
false.
So, retract/1 is really for doing one-at-a-time retractions but expects something shaped like the term you asserted, whereas retractall/1 only wants a head, treats it as a pattern, and will remove as many things as match the pattern.
This certainly helped me improve my understanding of Prolog, so I hope it helps you as well!
The definition of assert in swi-prolog is:
Assert a clause (fact or rule) into the database. The predicate asserta/1 asserts the clause as first clause of the predicate while assertz/1 assert the clause as last clause. The deprecated assert/1 is equivalent to assertz/1. If the program space for the target module is limited (see set_module/1), asserta/1 can raise a resource_error(program_space) exception. The example below adds two facts and a rule. Note the double parentheses around the rule.
Hence, it does not call or infer anything! It's just an assertion for the fact and the rule into the active memory.
I'm currently studying Prolog, and in one of the notes I'm reading an example is given of how to use the cut operator correctly. Consider the following function to remove all elements of a particular value from a list.
rm(_,[],[]).
rm(A,[A|L],R) :- rm(A,L,R).
rm(A,[B|L],[B|R]) :- rm(A,L,R).
Due to backtracking, this is not a correct definition of the function, and the function will return all sublists of the list obtained from removing some elements of a particular value, but not necessarily all of them. The notes I'm reading say that a correct way to fix this is to replace the second line by the line
rm(A,[A|L],R) :- !, rm(A,L,R)
But that replacing the line by
rm(A,[A|L],R) :- rm(A,L,R), !
is not correct. I'm not sure why the second example is an incorrect way to fix the function. In swipl, replacing the second term by these fixes seems to always return the same answer on the test cases I consider. What am I missing here?
Your example is a perfect example to illustrate why using the cut here is never a good idea.
Using rm(A,[A|L],R) :- !, rm(A,L,R). makes only sense if both the first and second argument are sufficiently instantiated. But if they are insufficiently instantiated, you get an incomplete answer like:
?- rm(X, [a], R).
X = a, R = []. % incomplete
This clearly misses an answer, as it constrains X to be a only. But if X is anything else, we get a different result, namely:
?- X = b, rm(X,[a],R).
R = [a].
Using the cut at the end as in rm(A,[A|L],R) :- rm(A,L,R), !. is even worse: First, all our assumptions so far must hold, and then additionally the third argument must not be instantiated. Otherwise we get additional incorrect solutions.
?- rm(a,[a],R).
R = [].
?- rm(a,[a],[a]).
true, unexpected. % incorrect
Just recall what we are asking here:
User: When removing a from the list [a] what do we get?
Prolog: Nothing, nil, nada.
User: But can't I have instead of nothing just [a]? Please!
Prolog: OK, I give in.
That's not the way you want to implement an accounting system.
So both uses of cuts are bad. But the second one is clearly worse for it has many more preconditions to remember and is also inefficient.
On the other hand there are some cases where you can use these predicates. But typically it is quite difficult to remember when this is safe. Thus such cuts are a permanent source of errors.
Is there any hope to get rid of all this fine print? Fortunately, there is a way out using if_/3 from library(reif) for SICStus|SWI. Download it and say:
:- use_module(reif).
rm(_,[],[]).
rm(A,[X|Xs], Ys0) :-
if_(A = X, Ys0 = Ys, Ys0 = [X|Ys]),
rm(A, Xs, Ys).
This program is comparably efficient but does not have any of the aforementioned defects:
?- rm(X, [a], R).
X = a, R = []
; R = [a], dif(X, a).
Note the second new answer! It says that for all X that are different to a, the list remains unchanged.
TL;DR: sibling(a,X) succeeds with the answer X = a, but sibling(a,a) fails.
I have the following Prolog file:
children(a, c).
children(a, d).
children(b, c).
children(b, d).
sibling(X, Y) :-
X \== Y, A \== B,
children(X, A), children(X, B),
children(Y, A), children(Y, B).
It seems clear enough to me, two person are siblings if their parents are the same. Also, a person is not their own sibling.
But when I tried to run some queries on GNU Prolog, I get some strange results:
| ?- sibling(a, b).
true ? a
true
true
yes
This is the intended behavior. a and b are siblings. There are three results, which is a bit weird, but I assume Prolog is binding A = c, B = d and A = d, B = c.
| ?- sibling(a, a).
no
I think this means a and a are not siblings.
| ?- sibling(a, X).
X = a ? a
X = b
X = a
X = b
X = a
X = b
X = a
X = b
(15 ms) yes
This is where I got stuck: It says X = a, which means sibling(a,a) is true, but sibling(a,a) failed in the previous query!
I feel that I'm not understanding what \== actually does in Prolog.
What is happening, and how do I fix this?
TL;DR: Use prolog-dif—or iso_dif/2 (on iso-prolog conforming systems like gnu-prolog)!
Good question, +1!
In fact, it's a question I have asked myself, and the answer has to do with logical-purity: logical purity is a central aspect of what
makes Prolog as a language so special, as it enables you to:
describe—not prescribe
write code that is relational—not just functional
think in terms of problems / solutions—not the individual steps of the search process itself
operate on a higher level—not get lost in nitty-gritty details
Unlike many other programming languages, Prolog programs have both procedural semantics (defining the execution steps and their order) and declarative semantics (allowing you to state relations that should hold and let the Prolog processor find a proper way of execution by itself).
But, beware: Prolog has some features that, when used, ruin declarative semantics. To prevent this, try to structure your application into two parts: an impure shell for dealing with side-effects (input/output) and a logically pure base which comprises pure monotonic Prolog code.
Try moving the inequality to the end of the predicate. Maybe it gives you true because it's not instantiated already.
sibling(X,Y):- children(X, A), children(X, B),
children(Y, A), children(Y, B),
X \== Y, A \== B.
I am quite rusty in prolog, but I am not sure why things like this fail:
frack(3).
frack(X) :- frack(X-1).
So, if I evaluate frack(4). from the interactive prompt with the above facts defined, I expect that it should not have to endlessly recurse, since 4-1 = 3. But I get this error in SWI-Prolog:
ERROR: Out of global stack
Try it:
?- 4-1 = 3.
false.
Why? Because 4-1 = -(4, 1), which clearly is not a number but a compound term.
To reason about integers in Prolog, use clpfd constraints, for example (using GNU Prolog or B-Prolog):
| ?- 4-1 #= X.
X = 3
In SWI-Prolog, the graphical tracer may be useful for you to see what happens:
?- gtrace, frack(4).
For more complex debugging, I recommend failure-slice as shown in false's answer.
Here is the reason for this non-termination. Your query does not terminate, because there is a failure-slice of your program that does not terminate:
?- frack(4).
frack(3) :- false.
frack(X) :-
frack(X-1), false.
You can fix this only by modifying something in the visible part. Three SO-answers suggest to use (is)/2. But this will not remove non-termination! In fact, using (is)/2 leads to essentially the same fragment:
?- frack(4).
frack(3) :- false.
frack(X) :-
Y is X - 1,
frack(Y), false.
At least, frack(4) now succeeds, but it will loop on backtracking. You have to change something in the visible part, like some test for X, in order to avoid non-termination. See failure-slice for more.
frack(X) :- frack(X-1).
should be
frack(X) :- Y is X - 1, frack(Y).
The way you wrote it, X-1 expression of the first level unifies with X variable at the next level, never going for the frack(3) fact.
Prolog doesn't do arithmetic unless you use the is operator:
frack(X) :- X1 is X-1, frack(X1).
What is the best way to express a total order relation in Prolog ?
For example, say I have a set of facts
person(tim)
person(ana)
person(jack)
...
and I want to express the following truth about a person's fortune: for each two persons X and Y, if not(X==Y), either X is richer than Y or Y is richer than X.
So my problem is that the richer clause should be capable of instantiating its variables and also to ensure that it is never the case that richer(X, Y) and richer(Y, X) at the same time.
Here is a better example to see what I mean:
person(tim).
person(john).
happier(tim, john).
hates(X, Y) :- person(X), person(Y), richer(Y, X).
hates(X, Y) :- person(X), person(Y), richer(X, Y), happier(Y, X).
Now the answer to the query hates(john, tim) should return true, because if richer satisfies the mentioned property, one of those two hates clauses must be true. In a resolution based inference engine I could assert the fact (richer(X, Y) V richer(Y, X)) and the predicate hates(john, tim) could be proved to be true.
I don't expect to be able to express this the same way in Prolog with the same effect. However, how can I implement this condition so the given example will work ?
Note also that I don't know who is richer: tim or john. I just now that one is richer than the other.
Thank you.
you cannot write in pure Prolog that a predicate should be a total order: that would require higher order logic since you want to declare a property about a predicate.
this is a predicate that checks if a relationship is total order on a finite set:
is_total_order(Foo,Set):-
forall(
(member(X,Set),
member(Y,Set)),
(
XY =.. [Foo,X,Y],
YX =.. [Foo,Y,X],
(call(XY);call(YX)), %checking if the relationship is total
\+ (call(XY),call(YX), X\=Y) %checking if it's an order
)
).
the operator =../2 (univ operator) creates a predicate from a list (ie: X =.. [foo,4,2]. -> X = foo(4,2)) and the predicate call/1 calls another predicate.
As you can see we use meta-predicates that operate on other predicates.
For an total order on infinite sets things get more complicated since we cannot check every single pair as we did before. I dont even think that it can be written since proving that a relationship is a total order isn't something trivial.
Still, this doesnt declare that a predicate is a total order; it just checks if it is.
So I believe your question is the best way to represent the relation between these 3 people. If you don't actually care about their wealth #'s, just their relative order, you could add predicates like this -
is_richer(tim, anna).
is_richer(anna, jack).
and then a predicate to find all people who X is richer than -
richer(X, Z) :-
is_richer(X, Z).
richer(X, Z) :-
is_richer(X, Y),
richer(Y, Z).
If your is_richer predicate contains cycles though (in this example, if you added is_richer(jack, tim)), this could explode. You need to track where you have visited in this tree.
An example run of richer would be:
?- richer(X, Y).
X=tim
Y=anna ;
X=anna
Y=jack ;
X=tim
y=jack ;
no