Why does this query unify with this clause in Prolog? - prolog

I think I have a fundamental misunderstanding about unification. Here are my two clauses:
test(func(X), X, 1) :- X == X.
test(func(X), Y, 0) :- X \== Y.
So- If I query test(func(X), Y, D), I would expect it to only be provable with the second clause, and D will be 0. This is because (I think\I am trying to) ensure that X must be equal to X, in the first clause. So my query shouldn't unify because X is not the same as Y. I thought == tests that the two operands are the same variables. And X and Y clearly aren't.
But the output:
| ?- test(func(X), Y, D).
D = 1
Y = X ? ;
D = 0
So it is saying that it unifies with the first clause if Y = X. But, Y is not equal to X. What am I misunderstanding here?

Your first answer, D = 1, Y = X accords with your first definition. I think you're expecting that when you query ?- test(func(X), Y, D). it should fail for the first definition, because the X and Y are different variables, but the first definition should only succeed if the two variables are identical.
However, in the head of your clause, you have the same variable appearing twice: test(func(X), X, 1) :- X == X. (As #CapelliC pointed out, X == X is superfluous here.) When you query ?- func(func(X), Y, D)., Prolog tries to unify this clause with the head of your first rule. It unifies func(X) with func(X) and Y with X and 1 with 1. Once this pattern-matching unification has succeeded, it then tests the body of the rule to see if the criteria are met. Since Y has been unified with X, the two variables will match the strict equality condition---during the pattern matching, you've unified Y with the same variable as X.
Note the following two queries:
?- X == Y.
false.
?- Y = X, X == Y.
X = Y.
The second is similar to what's happening with the query that's confusing you. If you rewrite your first rule in accordance with #CapelliC's suggestion,
test(func(X), Y, 1) :- X == Y.
Then it will function as expected, because, in this case, a free variable in the second argument will be unified with a different variable than that within the func/1 term, and then the two variables won't satisfy strict equality (but if the two variables are unified with a ground term, they will pass).

X == X it's a sort of tautology (always true), and clearly your first clause could equivalently be
test(func(X), X, 1).
I think you should write it like the second one
test(func(X), Y, 1) :- X == Y.

Related

Why do both predicates get evaluated?

I have this predicate with two clauses:
abs(X, Y) :- X < 0, Y is -X.
abs(X, X) :- X >= 0.
and I submit this to the interpreter:
?- abs(-5,W).
W = 5 ;
false.
?-
Why does it evaluate the second clause and return false? Is there a way around that?
You wrote two clauses that are disjoint on the 1st argument(X) and were surprised that Prolog backtracked into the 2nd one even though the first one was satisfied.
abs(X, Y) :- X < 0, Y is -X.
abs(X, X) :- X >= 0.
When the 1st clause was satisfied, the Prolog engine only knew that there was a 2nd clause that hadn't been evaluated; when you typed ";", it tried the 2nd clause, which failed. To see why, consider a slightly different (and not as good) version of your code:
abs2(X, Y) :- X =< 0, Y is - X.
abs2(X, Y) :- X >= 0, Y = X.
?- abs2(0, Y).
Y = 0 ;
Y = 0 ;
In this situation, even though the 1st clause succeeds, the 2nd clause can also succeed.
So, how to avoid this? It depends on what you want to accomplish. If you want to get all the answers, do something like this:
?- setof(W, abs(-5, W), Ws).
Ws = [5].
To print them all:
?- forall(abs(-5, W), format('W = ~q~n', [W])).
W = 5
If you want to tell the Prolog engine that your predicate is deterministic, you can use an if-then-else:
abs(X, Y) :-
( X < 0
-> Y is -X
; Y = X
).
This can also be written with a cut("!"), but it's often easier to understand with if-then-else.
And, if you're using the latest version of SWI-Prolog, you can use the "=>" notation:
abs(X, Y), X < 0 => Y is -X.
abs(X, Y) => true.

Why does my predicate not work, when a similar predicate does?

I have the following facts:
loves(andy, julia).
loves(andrew, maria).
loves(bob, sofia).
loved(juila).
loved(maria).
loved(sofia).
and I want to have two predicates:
do_love(X, Y) :- ...
is_loved(X, Y) :- ...
which returns Y as the name of the person, and X as the fact itself. For the loved fact, I wrote:
is_loved(X, Y) :- X = loved(Y), X.
which as expected, returns:
is_loved(X,Y).
X = loved(juila),
Y = juila ;
X = loved(maria),
Y = maria ;
X = loved(sofia),
Y = sofia.
However, when I write the predicate for the loves fact in a similar way:
do_love(X, Y) :- X = loves(X, Y), X.
it returns false for the query:
do_love(X,Y).
false.
I'm new to prolog, and can't really see why this is the case. Why does the query for is_loved work, while the one for do_love doesn't?
The problem is you're trying to unify X with two different values:
X = loves(...) and
loves(X, ...)
(I truncate using ... because those parts are irrelevant to what I'm saying).
In other words, your do_love predicate is saying "X must unify with a loves predicate" and also "X must unify with the first argument in a loves predicate". With the data set you've set up, no single value fulfills both requirements.
Depending on what you're trying to do, this might be what you want:
do_love(X, Y) :- loves(X, Y).
Sidenote 1: Predicates don't "return" values like they do in other languages with functions. You don't need the , X in your predicates for them to work.
Sidenote 2: The = is a "unify" operator, rather than an "assignment" like other languages. See this page for more info.

Fact formation with ceiling in prolog

Can I define a fact of the following form,
test(X, ceiling(sqrt(X))).
Where, X is related to ceiling(sqrt(X)).
I think , I could have done the following to receive the desired output,
test(X, Y) :- Y is ceiling(sqrt(X)).
You can define:test(X, ceiling(sqrt(X))).
This means that you have as fact atoms in the above form so if you query:
?- test(X, ceiling(sqrt(X))).
true.
because you defined this clause.
But note that if you query:
?- test(1.5, 2).
false.
It returns false because 2 is ceiling(sqrt(1.5)) but the predicate is waiting a syntax like ceiling(sqrt(1.5)) and not the result 2.
Another example:
?- test(1.5, Y).
Y = ceiling(sqrt(1.5)).
and
?- test(X,ceiling(sqrt(1.5))).
X = 1.5.
Also notice that :
test(X) :- X is ceiling(sqrt(X)).
is always failing for any input X (because there is no such X that equals to ceiling(sqrt(X)). )and querying test(X) will have instantiation problems due to is/2.
Maybe what you meant to write is:
test(X,X1) :- X1 is ceiling(sqrt(X)).
Sorry but I don't understand your clause
test(X) :- X is ceiling(sqrt(X)).
You're imposing the equation (not assignment: equation) " X = ceiling(sqrt(X)) ".
I think you're intention was
test(X, Y) :- Y is ceiling(sqrt(X)).
Is this what do you want?

Prolog: comparing predicate value with constant

I have some problems with prolog, specifically I can't compare a value of a predicate with a constant.
predicate(9).
compare(X,Y) :- X<Y.
Running the program:
?-compare(predicate(X),10).
Why doesn't it work? Thank you for your answers.
Predicates don't return values in the way that a function does.
This is C:
int nine() { return 9; }
int main() {
int x = nine(); /* x is now 9 */
}
This is Prolog:
% source
nine(9).
% from the top level
?- nine(X).
X = 9.
?- nine(X), X < 10.
X = 9.
?- nine(X), compare(C1, X, 10), compare(C2, 10, X).
X = 9,
C1 = (<),
C2 = (>).
Few things (trying not to use too much Prolog lingo):
What your predicate/1 and my nine/1 does is to unify its only argument with the integer 9. If the unification succeeds, the predicate succeeds, and now the argument is bound to 9. If the unification fails, the predicate fails.
?- nine(9).
true.
?- nine(nine).
false.
?- nine(X), nine(Y).
X = Y, Y = 9.
You will also notice that there is a standard predicate compare/3 that can be used for comparison of Prolog terms. Because predicates don't have a return value in the way that functions do, it uses an extra argument to report the result of the comparison. You could have instead tried something along the lines of:
% greater_than(X, Y) : true if X is greater than Y according
% to the standard order of terms
greater_than(X, Y) :- X #> Y.
But this is just defining an alias for #>/2, which is a predicate itself (but has been declared as an operator so that you can use it in infix notation).
?- #>(a, b).
false.
?- #>(b, a).
true.
Same goes for </2, which is a predicate for comparison of arithmetic expressions:
?- 2 + 4 =< 6.
true.
?- nine(X), X > 10 - X.
X = 9.
?- nine(X), X > 10.
false.
Like #Boris said before "Predicates don't return values in the way that a function does." Here you must try to instantiate the variables in the head of your rule.
If you are trying with you predicate compare/2 to find a number X greater than Y, and at the same time this number X should be a fact predicate/1, then add both conditions to the body of your rule or predicate compare/2
predicate(9).
compare(X,Y) :- predicate(X), X<Y.
Now if you consult:
?- compare(X,10).
The answer will be
X = 9
As you can see, 9 is smaller than 10, and at the same time 9 is a fact predicate/1. And that is the return value you are looking for.
Caution
Note that the operator >/2, requires that both sides are instantiated, so in this case you won't be able ask for the value Y in your predicate
?- compare(9, Y)
</2: Arguments are not sufficiently instantiated
Maybe and if it make sense, you can try to instantiate this variable to a fact predicate/1 too.
predicate(9).
predicate(10).
compare(X,Y) :- predicate(X), predicate(Y), X<Y.
?- compare(9,Y).
Y = 10

Prolog - Make two Instantiations Equal

I'm very new to Prolog so please bear with me.
Lets say I have the following:
foo(bar(a,b)).
foo(bar(b,a)).
Then I enter foo(X) as a query:
?- foo(X).
X = bar(a, b) ;
X = bar(b, a).
Prolog returns two instantiations of X to satisfy the query: bar(a, b) and bar(b,a).
Is there away I can make these two instantiations equivalent? Once Prolog instantiates X to bar(a,b), it won't instantiate it to bar(b,a).
So when I enter foo(X) as a query:
?- foo(X).
X = bar(a, b).
X was no instantiated as bar(b,a), because it's equivalent to bar(a,b). Is this possible to do with Prolog, or does it go against the fundamental principals of Prolog?
The first clause of symmetry/2 deals with cases in which both foo(bar(a,b)) and foo(bar(b,a)) occur. I use the standard order of terms in order to return only the former. Notice that the use of #< would have falsely excluded results like foo(bar(e,e)).
The second clause treats cases in which either foo(bar(c,d)) or foo(bar(d,c)) occur.
foo(bar(a, b)).
foo(bar(b, a)).
foo(bar(c, d)).
foo(bar(e, e)).
symmetry(X, Y):-
foo(bar(X, Y)),
foo(bar(Y, X)),
X #=< Y.
symmetry(X, Y):-
foo(bar(X, Y)),
\+ foo(bar(Y, X)).
Example of usage:
?- symmetry(X, Y).
X = a,
Y = b ;
X = Y, Y = e ;
X = c,
Y = d ;
false
Hope this helps!
Identity of literals it's the core of unification - the fundamental operation of Prolog algorithm - and then the answer to your question it's no, it's not possible to handle bar(a,b) as bar(b,a).

Resources