I have entered these statements into the prolog interpreter and am confused by the results. Shouldn't they return the same thing; true?
1 ?- 7 = 5 + 2.
false.
2 ?- 7 is 5 + 2.
true.
No, because =/2 does not mean assign in Prolog, but rather unify. And the unification algorithm does not know anything at all about arithmetic, just structure. So you can do some interesting things with arithmetic expressions in Prolog that are quite difficult to pull off in other languages:
?- X = 5 + 2.
X = 5+2.
It looks like nothing happened there, but what actually happened is X was given the value "5 + 2" as a structure. Put another way:
?- A + B = 5 + 2.
A = 5,
B = 2.
Or even:
?- X = 5 + 2, X =.. [Op|_].
X = 5+2,
Op = (+).
That last one might make more sense with the whole list though:
?- X = 5 + 2, X =.. Y.
X = 5+2,
Y = [+, 5, 2].
This is an effect of the remarkable "univ" operator, =../2, which is able to convert between Lisp-like lists and Prolog syntax, enabling you to do interesting construction and decomposition of structures in a generic fashion.
Now, is/2, on the other hand, does know about arithmetic. It unifies its left argument with the result of arithmetic simplification of its right. Do note that it only works in one direction:
?- 7 is 5 + 2.
true.
?- 5 + 2 is 7.
false.
You could say that =/2 is interested in structure and is/2 is interested in numeric equality. But it does mean that it's unusually easy to teach Prolog algebra:
simplify(X * Y + X * Z, X * (Y + Z)). % distributive property
simplify(X, X).
?- simplify(A * 3 + A * 4, Q).
Q = A* (3+4)
Now, this isn't perfect (note that we got 3+4 and not 7) and it's still a lot of work to make it really smart:
?- simplify(3 * A + 4 * A, Q).
Q = 3*A+4*A.
But that's a problem for another day.
Nutshell:
=/2 triggers unification
is/2 triggers arithmetic evaluation
Related
Need help creating a recursive clause is a rule: X is a power of 2 only if there is a Y such that when adding Y to Y the result is
X, and Y is a power of 2. in prolog
We are going to define this predicate recursively. The followings are the fact and rule for detecting whether a numeral
is a power of 2 or not:
• The base clause is a fact: 1 is a power of 2 (because 1=20);
• The recursive clause is a rule: X is a power of 2 only if there is a Y such that when adding Y to Y the result is
X, and Y is a power of 2.
For example, the following shows how the queries should be performed:
| ?- powerOf2(succ(succ(succ(succ(0))))).
true ?
yes
| ?- powerOf2(succ(succ(succ(0)))).
no
The first query shows that 4 is a power of 2; while the second shows that 3 is not.
can not use the built-in is/2 predicate to perform arithmetic
To make it easier to represent natural numbers in Peano notation, you can use the following predicate:
nat(0, 0).
nat(N, s(P)) :-
succ(M, N),
nat(M, P).
Examples:
?- nat(3, P).
P = s(s(s(0))) ;
false.
?- nat(5, P).
P = s(s(s(s(s(0))))) ;
false.
To get the double of a Peano number, use the predicate:
double(0, 0).
double(s(A), s(s(B))) :-
double(A, B).
Examples:
?- nat(1, P), double(P, D).
P = s(0),
D = s(s(0)) ;
false.
?- nat(3, P), double(P, D).
P = s(s(s(0))),
D = s(s(s(s(s(s(0)))))) ;
false.
To check whether a Peano number is a power of two, use the predicate:
power_of_two(s(0)).
power_of_two(s(s(N))) :-
double(M, s(s(N))),
power_of_two(M).
Example:
?- between(1,9,N), nat(N,P), power_of_two(P).
N = 1,
P = s(0) ;
N = 2,
P = s(s(0)) ;
N = 4,
P = s(s(s(s(0)))) ;
N = 8,
P = s(s(s(s(s(s(s(s(0)))))))) ;
false.
Need help creating a recursive clause
The recursive clause will be:
power_of_two(1).
power_of_two(X) :-
X > 1,
Y is X / 2,
power_of_two(Y).
A base case which handles 1 being a power of two. And a case which handles when X is greater than one, Y is half X and recursively checks that Y is a power of two.
can not use the built-in is/2 predicate to perform arithmetic
You can't, but I can for the sake of illustrating the recursive clause you asked about. I'm assuming that since it tells you to use "succ(succ(succ(succ(0))))" you already have met that and have some code for adding/subtracting/dividing which you can reuse to replace Y is X / 2.
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.
Can you help me understand the engine of answering the next queries?
?- _ = _.
?- _ = 1.
?- A = _, B = _, C = A + B + 1.
And some extra query (not related to anonymous variables):
?- B = A + 1, A = C, C = B - 1.
I know the answers to above queries, but I want to understand how prolog find those answers :)
Thanks!
_ is called the _anonymous variable. Each occurrence of _ is a different variable. You can observe it easily by using the standard write_canonical/1 built-in predicate. For example:
| ?- write_canonical(_ = _).
=(_279,_280)
yes
A variable can be unified with any term, including other variable, as you observe in your queries. Note that the standard =/2 built-in predicate performs unification, not equality or arithmetic expression evaluation. Unification takes two terms and succeeds if the two terms are the same or can be made the same by unifying any variables in the terms. For example:
| ?- A + 1 = 2 + B.
A = 2
B = 1
(1 ms) yes
A query such as:
| ?- write_canonical(B = A + 1), nl, B = A + 1, write_canonical(B).
=(_279,+(_280,1))
+(_280,1)
B = A+1
yes
unifies the variable B with the compound term +(A,1). _279 and _280 are the internal variable representation for, respectively, B and A. Different Prolog systems print these internal representation differently. For example, using SWI-Prolog:
?- write_canonical(B = A + 1), nl, B = A + 1, write_canonical(B).
=(_,+(_,1))
+(_,1)
B = A+1.
Regarding your extra query, B = A + 1, A = C, C = B - 1, it creates cyclic terms. Consider the simpler query:
| ?- X = f(X).
The result and consequent variable binding report by the Prolog top-level depends on a specific Prolog system handles cyclic terms. For example, in GNU Prolog you will get:
| ?- X = f(X).
cannot display cyclic term for X
yes
while SICStus Prolog reports:
| ?- X = f(X).
X = f(f(f(f(f(f(f(f(f(f(...)))))))))) ?
Cyclic terms are useful for some applications, e.g. coinductive logic programming. But the handling of cyclic terms is not standardized and varies among Prolog systems. The ISO Prolog standard provides a built-in predicate, unify_with_occurs_check/2, that checks if unification will create a cyclic term, preventing it. For example:
| ?- unify_with_occurs_check(X, f(X)).
no
| ?- unify_with_occurs_check(X, Y).
Y = X
(1 ms) yes
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
I am trying to write a function - decListRange(X,List) which give a list in range [X-1:1] by descending order. For example -
decListRange(9,List).
Will give -
List = [8,7,6,5,4,3,2,1].
I tried the following but it goes into infinite loop -
decListRange(1,[]) :- !.
decListRange(X,[H|Rest]) :-
H = X-1, NextX = X - 1 ,decListRange(NextX,Rest).
You have two problems. The first real one is that you need to use is instead of =:
H is X-1
This is needed to trigger arithmetic evaluation. Your second problem isn't a real problem but speaks to a bigger misunderstanding, which is that H and NextX are equivalent. Because Prolog only has bindings and not "assignables" as it were, you should never really need to create two "variables" with the same binding. There's no state being kept around for you to modify later.
Cleaning up both you get this:
decListRange(1, []) :- !.
decListRange(X, [H|Rest]) :-
X > 1,
H is X-1,
decListRange(H, Rest).
Edit 2: a clpfd implementation
:- use_module(library(clpfd)).
declist(N, L) :- N == 1, !, L = []. % green cut
declist(1, []).
declist(N, [N1|Ns]) :-
N #> 1,
N1 #= N - 1,
declist(N1, Ns).
This one has the properties #false mentions below in the comments:
?- declist(3, L).
L = [2, 1] ;
false.
?- declist(3, [2,1]).
true ;
false.
?- declist(N, [3,2,1]).
N = 4.
?- declist(N, X).
N = 1,
X = [] ;
N = 2,
X = [1] ;
N = 3,
X = [2, 1] ;
N = 4,
X = [3, 2, 1] ;
N = 5,
X = [4, 3, 2, 1] .
Edit: a short interlude on the difference between = and is.
In procedural languages = is almost always syntax for assigning a particular value to a variable. In Prolog, variables are bindings, and once established they cannot be directly modified by reassigning the variable a different value. Instead they work more like variables in math and logic, where the variable "stands in" for interesting values, but those values are themselves basically immutable. In Prolog, = essentially asks the unification engine to establish bindings. So if you were to do something like this:
?- name(X, Y) = name(bob, tony).
Prolog responds with variable bindings:
X = bob,
Y = tony.
Once those bindings exist, contradictory bindings will fail and affirmative bindings will succeed:
?- name(X, Y) = name(bob, tony), X = bob.
X = bob,
Y = tony.
?- name(X, Y) = name(bob, tony), X = william.
false.
The unification algorithm itself doesn't know anything about arithmetic. This has the pleasant side-effect that you can use any expression raw. For instance:
?- Expr = X + 3, Z + Q = Expr.
Expr = Z+3,
X = Z,
Q = 3.
This is probably really surprising looking. You may expect that somehow Prolog was smart enough to keep the expression around because it noticed X was a variable or something, but that isn't true either:
?- X = 4, Expr = X + 3, Z + Q = Expr.
X = 4,
Expr = 4+3,
Z = 4,
Q = 3.
Another way of looking at this is that Prolog is considering + to be just another operator, so X+3 is a fact just like add(X, 3) that doesn't necessarily have any special meaning. Whichever way you look at it, the is/2 operator exists to apply arithmetic reasoning and produce a value:
?- X = 4, Expr is X + 3.
X = 4,
Expr = 7.
Notice that Expr has the computed value but none of the original structure:
?- X = 4, Expr is X + 3, Z + Q = Expr.
false.
In practice, if you need to do a lot of reasoning with arithmetic, you will want to use a library like clpfd or clpqr depending on whether you're interested in integers or reals. This library enables you to do more interesting things more easily, like specify that an equation holds for values in a certain range and get those values out.