Why does 'is' in swi-prolog behave differently if sides are switched? - prolog

I'm using swi-prolog version 6.6.6 if that matters.
As far as I can tell they should be equivalent since the only difference is which side of the 'is' everything is on. Why do they give different results?
[trace] 48 ?- mod(3,3) is 0.
false.
[trace] 49 ?- 0 is mod(3,3).
true.

What every one else said. is/2 evaluates the right-hand side as an arithmetic expression and unifies the result of that evaluation (assuming that it was, in fact, a valid arithmetic expression, with the left hand side. So you can say things like:
X is 3+2 * 4 mod 3
0 is 3+2-5
And it's not really intended for arithmetic comparisons. But that would be clear if you had read the documentation for is/2:
-Number is +Expr
True when Number is the value to which Expr evaluates.
Typically, is/2 should be used with unbound left operand.
If equality is to be tested, =:=/2 should be used. For example:
?- 1 is sin(pi/2). Fails! sin(pi/2) evaluates to the float 1.0,
which does not unify with the integer 1.
?- 1 =:= sin(pi/2). Succeeds as expected.
And if you chase down the docs for =:=/2 and its relatives, you discover
+Expr1 > +Expr2.
True if expression Expr1 evaluates to a larger number than Expr2.
+Expr1 < +Expr2.
True if expression Expr1 evaluates to a smaller number than Expr2.
+Expr1 =< +Expr2.
True if expression Expr1 evaluates to a smaller or equal number to Expr2.
+Expr1 >= +Expr2.
True if expression Expr1 evaluates to a larger or equal number to Expr2.
+Expr1 =\= +Expr2.
True if expression Expr1 evaluates to a number non-equal to Expr2.
+Expr1 =:= +Expr2.
True if expression Expr1 evaluates to a number equal to Expr2.
A little curiousity won't hurt you.

Related

Prolog: what is difference between, for example, X is 3 and 3 is X?

three(X) :- 3 is X.
three2(X) :- X is 3.
Requests three(3), three(5) and three2(3), three2(5) respectively have the same answers.
But three2(X) has answer 3, while three(X) has answer "Arguments are not sufficiently instantiated".
If there's enough data to solve that three(3) is true and three(5) is false, why there's not enough data to find that X is equals 3 when we request for the value of X?
That's because is/2 is the numeric expression evaluator of Prolog. Everything on the Right Hand Side of is/2 must be fully instantiated so that the expression can then be evaluated to a number (possibility missed: evaluate to something else than numbers). The result is then unified with the Left Hand Side of is/2. This succeeds if the LHS is an unbound variable or the same as the result obtained.
In your case, you can make the predicate three/1 symmetric by just unifying, as there is really nothing to evaluate:
three_sym(X) :- 3 = X.
Succeeds with 3 and outputs the answer X = 3 for an unbound X.

How do you know if the elements of a list are odd or even?

I wrote two predicates to find out if the elements that make up a prolog list are odd or even but it doesn't work. Why ?
odd([X]):- (X mod 2) = 0.
odd([T|Q]):- (T mod 2) = 0, odd(Q).
It did not work because:
The most important thing: = checks for unification. It does not evaluate, meaning that 0 and (X mod 2) can never be made equal. Use =:= for comparing arithmetic terms, evaluating both sides, or is if only the right side needs to be evaluated.
You confused even with odd. An odd number modulo 2 should result in 1.
Additionally: You have no pattern for an empty list. But the second rule already covered the first, so that can just be replaced.
Put together in code:
odd([]).
odd([T|Q]):- 1 is (T mod 2), odd(Q).
Examples:
?- odd([4]).
false.
?- odd([3]).
true.
?- odd([3,5]).
true.
?- odd([3,6]).
false.

Prolog: why is true == not(not(true)) -> false?

Obviously true = not(not(true)) has to be false, because = tries to unify the atom true with the term not(not(true)) (without evaluating the term), which is false, since the terms are not identical.
However, I thought == really compares whatever is evaluated. Thus, I thought true == not(not(true)) should evaluate to true == true, just like (for arithmetic operators) 4 =:= 2 + 2 would evaluate to 4 =:= 4 and return true.
...but this is what I get in SWI-Prolog:
?- true == not(not(true)).
false.
What am I getting wrong?
(==)/2 does not compare whatever is evaluated. It does not evaluate its arguments. It only succeeds if the arguments are already instantiated to matching terms.
In prolog, not(not(true)) is a compound term, which is the term not/1 with a single argument, not(true), itself being a term not/1 of one argument consisting of the term true/0 which has no arguments. It doesn't have a value. It doesn't even get "executed" except in certain contexts. In Prolog, the predicate not/1 succeeds if it's argument fails, and it fails if its argument succeeds. This isn't the value or functional result, but a behavior. This is assuming that it appears in a context such as the following:
not(not(true)),
write('This will be written out because not(not(true)) succeeded'), nl.
The expression true == not(not(true)) in Prolog is a compound term, equivalent to:
'=='(true, not(not(true)))
In this context, not(not(true)) is not evaluated. Prolog will first exercise the (==)/2 equivalence operator, which succeeds if its arguments are instantiated to the same term. Are the terms true and not(not(true)) in Prolog the same (or equivalent)? No they are not. One is simple term with no arguments (true/0). The other is a compound term: a term with one argument that is itself a term with one argument. Thus the (==)/2 fails here.
Note that (=:=)/2 is quite different. It is an operator that compares results of arithmetic expressions. The arguments must be evaluable arithmetic expressions and (=:=)/2 will succeed if they evaluate to the same result, and it will fail if they do not.

Prolog converting text to number and doing arithmatic operations

I working in prolog for first time.
I am trying to convert operations in text.
Such as,
THREE + THREE = SIX
should return true.
I tried this.
I am getting error on last line and when I try add(ONE,ONE,TWO) it returns false instead of true.
numericValue(ONE, 1).
numericValue(TWO, 2).
numericValue(THREE, 3).
numericValue(FOUR, 4).
numericValue(FIVE, 5).
numericValue(SIX, 6).
numericValue(SEVEN, 7).
numericValue(EIGHT, 8).
numericValue(ZERO, 0).
numericValue(NINE, 9).
add(num1,num2,num3):-
numericValue(num1,a),
numericValue(num2,b),
numericValue(num3,c),
(c =:= a+b -> true ; false).
istBiggerThen(XinEng,YinEng) :-
numericValue(XinEng, X),
numericValue(YinEng, Y),
( X < Y -> true ; false).
A + B = C :- add(A,B,C).
Error on last line is
ERROR: /home/name/prolog_examples/crypt.pl:24:
No permission to modify static procedure `(=)/2'
literals (lower-case) vs. Variabls (upper-case):
as #lurker pointed out, you have your atoms and variables mixed up. So your facts should look something like this:
text_to_number(one, 1).
text_to_number(two, 2).
text_to_number(three, 3).
%% etc...
while your rules will need to use variables, like so:
add(A_Text, B_Text, C_Text) :-
text_to_number(A_Text, A_Num),
text_to_number(B_Text, B_Num),
C_Num is A_Num + B_Num,
text_to_number(C_Text, C_Num).
bigger_than(A_Text, B_Text) :-
text_to_number(A_Text, A_Num),
text_to_number(B_Text, B_Num),
A_Num > B_Num.
The reason reason why add(ONE, ONE, TWO) turns out false is because your original rule for add/3 only defines relationships between the atoms num1, num2, num3, a, b, c. When you query add(ONE, ONE, TWO) Prolog tries to unify the variables with the atoms in the head of your rule, which is add(num1, num2, num3). Because you have ONE as the first and second argument of your query, this unification is impossible, since ONE = ONE but num1 \= num2. As there are no further rules or facts for add/3, the query simply returns false.
Using the pattern (|Condition| -> true ; false):
Statements in the body of a clause (i.e., to the right of the :- operator) is evaluated to be either true or false, so you will almost never need to use the pattern (|Condition| -> true ; false). E.g. C_Num is A_Num + B_Num is true iff C_Num can be unified with the sum of A_Num and B_Num, or else it is false, in which case Prolog will start back tracking.
Using =:=/2 vs. is/2:
=:=/2 checks for the equality of its first argument with the value of its second argument, which can be an arithmetical expression that can be evaluated using is/2. Query ?- X =:= 2 + 2 and you'll get an instantiation error, because =:=/2 cannot compare a free variable to a mathematical expression. is/2, on the other hand, unifies the variable on the left with the value of the expression on the right: ?- X is 2 + 2. X = 4.
Your use of =:=/2 would work (provided you straightened out the variable-atom thing), but your rule describes an inefficient and roundabout solution for the following reason: since numericValue(Num3,C) precedes evaluation of the arithmetic, Prolog will first unify numericValue(Num3,C) with the first fitting fact, viz. numericValue(one, 1) then test if 1 =:= A + B. When this fails, Prolog will unify with the next fact numericValue(two, 2) then test if 2 =:= A + B, then the next... until it finally happens upon the right value. Compare with my suggested rule: the numeric values A_Num and B_Num are summed with C_Num is A_Num + B_Num, unifying C_Num with the sum. Then Prolog unifies text_to_number(C_Text, C_Num) with the single fitting fact that has the appropriate value for C_Num.
Defining operators:
When a term appears on the right of a :-, or on the top level of the program, is being defined. However, you cannot simply redefine predicates (it can be done, but requires some bookkeeping and special declarations. Cf., dynamic/1). Moreover, you wouldn't want to redefine core terms like +/2 and =/2. But you can define your own predicates with relative ease. In fact, going crazy with predicate definitions is one of my favorite idle things to do with Prolog (though I've read cautions against using unnecessary operators in practice, since it makes your code recondite).
Operators are declared using op/3 in a directive. It has the signature op(+Precedence, +Type, :Name) (Cf., the SWI-Prolog documentation):
:- op(200, xfx, user:(++)).
:- op(300, yfx, user:(=::=)).
A ++ B =::= C :- add(A, B, C).
In action:
?- one ++ two =::= X.
X = three.

Prolog is vs = with lists

Why does this fail L is [1,2,3,4], and this works: L = [1,2,3]?
But L is 1, and L = 1 both work the same.
is should only be used when evaluating arithmetic operations on the right-hand side.
i.e.:
X is 1 + 2 + 3
is/2 evaluates the right-hand structure as an arithmetic expression. If it is not a valid arithmetic expression or a number, is/2 fails. Otherwise, the number to which the arithmetic expression evaluted is unified with the [presumably] unbound left-hand value.

Resources