I'm new to Prolog, so please be gentle.
This is my rule:
solve(X) :- A = B, A is (7 * (X - 2)), B is (3 * (X + 4)).
Obviously, the correct answer here is 6.5
. If I give that to Prolog, it confirms:
| ?- solve(6.5).
yes
However, if I ask Prolog to do the dirty work, it throws an error:
| ?- solve(X).
uncaught exception: error(instantiation_error,(is)/2)
I fully concede that whatever is going on here is due to my misunderstanding of Prolog. Can someone explain to me how I might get this to work or why it won't work?
You can use a library for this, available in SWI-Prolog at least: library(clpr) and library(clpq).
Here from the top level for Reals:
?- use_module(library(clpr)).
true.
?- {7 * (X - 2) = 3 * (X + 4)}.
X = 6.5 ;
false.
Or, if you use Rationals:
?- use_module(library(clpq)).
true.
?- {7 * (X - 2) = 3 * (X + 4)}, R is float(X).
X = 13 rdiv 2,
R = 6.5.
If you want to do it yourself, it will be of course much more work. You would have to write code like
...,
( ground(X)
-> 7 * (X - 2) =:= 3 * (X + 4)
; X is (3*4 + 2*7) / (7 - 3)
),
...
By the way, what you are doing: A = B, A is ..., B is ...
.
This is a bit dangerous, for example:
?- A = B, A is 3 - 2, B is sin(pi/2).
false.
?- 3 - 2 =:= sin(pi/2).
true.
3 - 2
evaluates to the integer 1; then, sin(pi/2)
evaluates to the floating point number 1.0, and this does not unify with the integer 1. So, the first query fails!
?- 1 = 1.0.
false.
In Prolog, is
is an arithmetic evaluation operator. It calculates the result of an expression on its right side, and assigns it to a variable on its left side.
The expression to be evaluated must contain only numbers and arithmetic operators/functions. In other words, to evaluate an expression, is
must already know all the numbers in it.
Another way of saying this is that is
is "unidirectional", unlike the =
which is bi-directional. Which is what you expected. And that is the meaning of the error that you got.
Solving such equations - constraints - is a job for a constraint solver.
Prolog works by unification. It tries to make structures the same.
So, for example, if I try to unify [3, X, 5]
with [3, 4, 5]
that works fine and X = 4
.
In your code you are first saying A = B
. That's fine as initially A
and B
are not instantiated so you are basically tying their destinies to each other - if A
is later instantiated then B
automatically is too, or visa-versa.
Then you go on to ask A is (7 * (X - 2))
. Now if you have already unified X
with 6.5
then this can be evaluated - A
is then unified with 7 * (6.5 - 2)
or 31.5
. But remember that A
was already unified with B
, so B
now also is 31.5
.
Now you say B is (3 * (X + 4))
. So with X
unified to 6.5
and B
unified with 31.5
this is the same as 31.5 is (3 * (6.5 + 4))
. The right hand side is 31.5
so this is 31.5 is 31.5
which is true.
So, solving for solve(6.5)
works.
However, if you try to solve for X
then the first predicate works just fine. But the second one doesn't. It's like me asking "What's 7 times the number that is 2 less than the number I'm thinking of?" Unless I tell you the number I'm thinking of you can't give me an answer. The same for Prolog. It gets stuck and reports an error.