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:
Or, if you use Rationals:
If you want to do it yourself, it will be of course much more work. You would have to write code like
By the way, what you are doing:
A = B, A is ..., B is ...
. This is a bit dangerous, for example: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!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 andX = 4
.In your code you are first saying
A = B
. That's fine as initiallyA
andB
are not instantiated so you are basically tying their destinies to each other - ifA
is later instantiated thenB
automatically is too, or visa-versa.Then you go on to ask
A is (7 * (X - 2))
. Now if you have already unifiedX
with6.5
then this can be evaluated -A
is then unified with7 * (6.5 - 2)
or31.5
. But remember thatA
was already unified withB
, soB
now also is31.5
.Now you say
B is (3 * (X + 4))
. So withX
unified to6.5
andB
unified with31.5
this is the same as31.5 is (3 * (6.5 + 4))
. The right hand side is31.5
so this is31.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.