SWI-Prolog: Call 3=2+1 -> Fail: 3=2+1 - prolog

I'm working on something in Prolog and I wanted to check, at some point in my proogram, if some variable1 equals variable 2 + 1 (var1=var2+1). It said false. Variable1 is equal to 3 in my case, and var2 is equal to 2. It doesn't register as true and I can't understand why. I tried to 'trace' it, but still can't understand what the problem is, it just fails.

In Prolog 2+1 is just 2+1, or more canonical +(2,1). After all, it is only because some people see + as addition that 2+1 is equivalent to 3.
You can use is/2 [swi-doc] to evaluate an arithmetic expression, for example:
?- X is 2+1.
X = 3.
?- 3 is 2+1.
true.
You can also =:=/2 [swi-doc] to check if the two operands are equivalent if these are evaluated arithmetically:
?- 3 =:= 2+1.
true.
?- 4 =:= 2+1.
false.

Related

In prolog, why is `(1+2) is (2+1)` false?

I'm trying to learn some prolog using the gprolog tool. I'm trying to see if lists sum up to the same value. I'm trying to understand why this expression is false.
{trace,1}
| ?- (2+1) is (1+2).
2 2 Call: 2+1 is 1+2 ?
2 2 Fail: 2+1 is 1+2 ?
no
Shouldn't 1+2 and 2+1 be equivalent because addition is associative?
It's simple because is evaluates the right-hand side and tries to unify it with the left-hand side.
Thus you get:
(2+1) = 3.
These two don't look the same (in fact, the "term" on the left-hand side is the prettyprinted structure +(2,1) as you can check by calling write_canonical(2+1).) and = (which is "unification", not comparison or assignment) fails.
What you want in his case is
?- 2+1 =:= 2+1.
true.
which performs numeric evaluation on both left-hand and right-hand sides, and then numerically compares the results.
Which is why this fails:
?- X =:= 2+1.
ERROR: Arguments are not sufficiently instantiated
but this succeeds:
?- X = 3, X =:= 2+1.
X = 3.
The two terms 1+2 and 2+1 are not equivalent. If you evaluate them as arithmetic expression, they have equal numeric values:
?- 1+2 =:= 2+1. % arithmetic equality
Alternatively, you could evaluate explicitly both sides and then compare:
?- X is 1 + 2, Y is 2 + 1, X == Y.
But this has its own different semantics. For example:
?- X is sin(pi/2), X == 1. % no!
?- X is sin(pi/2), X =:= 1. % yes
Unification with = and equivalence with == are two different things. This is what unification can do:
?- X + 2 = 1 + Y.
Equivalence checks if the two terms are equivalent. +(1, 2) and +(2, 1) are not equivalent; the functor is the same but the two arguments are swapped.

Prolog - equal operator wrapping

equal(a, b) :- (a = b).
I defined equal.
1 ?- [index].
true.
2 ?- equal(1, 1).
false.
3 ?- 1 = 1.
true.
When I run
equal(1, 1)
it returns false.
Why does it return false and how can i fix it?
First of all, you should write equal(A, B) :- A = B instead of what you've written. The difference is that a and b are constants and A and B are variables that can be unified with values. I guess then it should work for your example.
But you should note that "=" predicate just tries to unify its arguments. So when you ask "1 = 1" the result is true because 1 unifies with 1. But when you ask "2 + 2 = 4" (or equal(2 + 2, 4)) the result will be false because this operator does not evaluate arithmetic operations. If comparing arithmetic expressions is what you want to do use =:= operator instead:
equal(A, B) :- A =:= B.

Why `X=1,X=1.` prints `X=1` instead of `true`

I'm learning the basics of Prolog and I was wondering why the following line prints X = 1 instead of true?
?- X=1,1=X.
X = 1.
--
The first X=1 in my command is an assignment, and the second one will be a check of equality.
There are no assignments or equality tests in your query, only unification of terms. The query succeeds by unifying the variable X with 1 and that's what the top-level reports: it tells which variable bindings makes the query true.
After the first goal in the conjunction, X = 1, succeeds, the second goal is the unification 1 = 1, which trivially succeeds.
P.S. Also note that Prolog systems differ in the way they report successful queries. Some print true, others print yes (the traditional way that successful queries are reported).
When the answer is true and a value is bound to variable at the top level, the value of the variable is displayed, which implies the result was true.
Here are some examples.
test_01 :-
X = 1,
X = 1.
test_02 :-
X = 1,
X = 2.
test_03(X) :-
X = 1,
X = 1.
test_04(X) :-
X = 1,
X = 2.
and when the examples are run from the top level using SWI-Prolog
?- test_01.
true.
?- test_02.
false.
?- test_03(X).
X = 1.
?- test_04(X).
false.
Here are some examples that are done only in the top level
?- X=1.
X = 1.
?- 1=1.
true.
?- 1=0.
false.
?- 1==0.
false.
The first X=1 in my command is an assignment, and the second one will be a check of equality.
X=1 is not an assignment it is a unification of the integer 1 to the variable X. The second X=1 is not a check of the equality, it is another unification of X to 1, but since X is bound to 1 by this time, it is really a different unification.
To do equality checking in Prolog use ==, e.g.
?- 1 == 1.
true.
?- 1 == 2.
false.
Also , is the logical and, so if
?- X = 1.
X = 1.
then 1 is bound to X and is true and similar for the second line in your question.
However the code has to be also viewed as
?- true,true.
true.
as opposed to
?- true,false.
false.
While ; is logical or
?- true;true.
true ;
true.
?- true;false.
true ;
false.
?- true;false;true.
true ;
true.
?- false;true.
true.
?- false;false.
false.
Notice that the first 3 answers have 2 results, but the last two answers have 1 result.

Prolog only check variable is instantiated

In Prolog, is it possible to check if the variable is certain value only if the variable is instantiated.
? - my_rule(X).
my_rule(X):-
X = 4,
write('continue').
Here I am trying to check if the X is 4, if the X is 4 then we continue, but I also want the rule to continue if the X is _, but when it is called with something else, like X is 3 then it should not continue.
So the results would look like this:
?- my_rule(X).
continue
true.
?- my_rule(4).
continue
true.
?- my_rule(3).
false.
Have a look at var/1, atom/1 and ground/1:
var(X) is true if and only if X is a variable.
?- var(X), X= 1.
X = 1.
?- X=1, var(X).
false.
?- X=f(Y), var(X).
false.
atom(X) is true if X is an atom.
?- atom(a).
true.
?- atom(f(a)).
false.
?- atom(X).
false.
ground(X) is true if X is ground (does not contain variables).
?- ground(f(a)).
true.
?- ground(f(X)).
false.
The three predicates are deterministic (i.e. do not backtrack) and you can safely negate them.
Your code become something like this:
my_rule(4) :-
% handle the 4 case
my_rule(X) :-
var(X),
% general case
I'm just not sure if this is, what you want. In most programs, there should be no necessity to handle the variable only case separately. Also be aware that such meta-logical tests are outside the scope of classical logic. If compare the queries X = 1, var(X) and var(X), X = 1, you can see that the conjunction is not commutative anymore but in logic A ∧ B = B ∧ A holds.
You can use double negation ( \+(\+(...)) ):
In your example:
my_rule(X):-
\+(\+(X = 4)),
write('continue').
my_rule(X):-
check(X),
write('continue').
% A fact used to check a value.
check(4).
% A predicate that checks if X is unbound, e.g. a variable.
check(X) :-
var(X).
Verification of desired results.
?- my_rule(X).
continue
X = 4 ;
continue
true.
?- my_rule(4).
continue
true ;
false.
?- my_rule(3).
false.

Prolog - ASSERT and RETRACT

I was wondering, I am aware you can use assert to add facts or rules or whatever if you have declared the predicate to be -:dynamic, but this only allows the changes that are made to be kept in that session only, e.g. if you close the Prolog window then the database changes are lost.
So I was wondering, is there any way of making it so that the assert and retract predicates can make permanent changes to the Prolog .pl file?
Thanks
I can suggest you a very simple way of doing this.
1 ?- assert(a(1)).
true.
2 ?- assert(a(2)).
true.
3 ?- assert(a(3)).
true.
4 ?- a(A).
A = 1 ;
A = 2 ;
A = 3.
5 ?- tell('a_db.txt'), listing(a), told.
true.
Then close session, reopen.
1 ?- a(A).
ERROR: toplevel: Undefined procedure: a/1 (DWIM could not correct goal)
2 ?- ['a_db.txt'].
% a_db.txt compiled 0.00 sec, 516 bytes
true.
3 ?- a(A).
A = 1 ;
A = 2 ;
A = 3.
4 ?- listing(a).
:- dynamic a/1.
a(1).
a(2).
a(3).
true.

Resources