Why can't my rule solve for X in a simple alge

2019-07-10 11:16发布

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?

3条回答
甜甜的少女心
2楼-- · 2019-07-10 11:35

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.
查看更多
祖国的老花朵
3楼-- · 2019-07-10 11:39

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.

查看更多
狗以群分
4楼-- · 2019-07-10 12:00

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.

查看更多
登录 后发表回答