为什么我的规则不能求解简单代数方程中的 X?
Why can't my rule solve for X in a simple algebraic equation?
我是 Prolog 的新手,所以请保持温柔。
这是我的规则:
solve(X) :- A = B, A is (7 * (X - 2)), B is (3 * (X + 4)).
显然,这里的正确答案是6.5
。如果我将其提供给 Prolog,它会确认:
| ?- solve(6.5).
yes
但是,如果我要求 Prolog 执行脏活,它会抛出错误:
| ?- solve(X).
uncaught exception: error(instantiation_error,(is)/2)
我完全承认这里发生的一切都是由于我对 Prolog 的误解。有人可以向我解释我如何使它起作用或为什么它不起作用吗?
在 Prolog 中,is
是算术求值运算符。它在右侧计算表达式的结果,并将其分配给左侧的变量。
要计算的表达式只能包含数字和算术 operators/functions。换句话说,要计算一个表达式,is
必须已经知道其中的所有数字。
另一种说法是 is
is "unidirectional",与双向的 =
不同。这是你所期望的。这就是你得到的错误的意思。
求解此类方程式 - 约束 - 是 constraint solver 的工作。
Prolog 通过统一工作。它试图使结构相同。
因此,例如,如果我尝试将 [3, X, 5]
与 [3, 4, 5]
统一,效果很好,而 X = 4
.
在你的代码中你首先说 A = B
。这很好,因为最初 A
和 B
没有被实例化,所以你基本上是将它们的命运联系在一起 - 如果 A
稍后被实例化,那么 B
也会自动实例化,或者签证-相反。
那你接着问A is (7 * (X - 2))
。现在,如果您已经将 X
与 6.5
统一,那么可以对其进行评估 - A
然后与 7 * (6.5 - 2)
或 31.5
统一。但是记住 A
已经和 B
统一了,所以 B
现在也是 31.5
.
现在你说B is (3 * (X + 4))
。因此 X
统一为 6.5
,B
统一为 31.5
这与 31.5 is (3 * (6.5 + 4))
相同。右边是 31.5
所以这是 31.5 is 31.5
这是真的。
所以,求解 solve(6.5)
是可行的。
但是,如果您尝试求解 X
,那么第一个谓词就可以正常工作。但是第二个没有。就像我问 "What's 7 times the number that is 2 less than the number I'm thinking of?" 除非我告诉你我在想的数字你不能给我答案。 Prolog 也一样。卡住报错
您可以为此使用库,至少在 SWI-Prolog 中可用:library(clpr) 和 library(clpq)。
这里来自雷亚尔的顶层:
?- use_module(library(clpr)).
true.
?- {7 * (X - 2) = 3 * (X + 4)}.
X = 6.5 ;
false.
或者,如果您使用 Rationals:
?- use_module(library(clpq)).
true.
?- {7 * (X - 2) = 3 * (X + 4)}, R is float(X).
X = 13 rdiv 2,
R = 6.5.
如果你想自己做,当然会多很多工作。您将不得不编写类似
的代码
...,
( ground(X)
-> 7 * (X - 2) =:= 3 * (X + 4)
; X is (3*4 + 2*7) / (7 - 3)
),
...
顺便说一句,你在做什么:A = B, A is ..., B is ...
。
这个有点危险,例如:
?- A = B, A is 3 - 2, B is sin(pi/2).
false.
?- 3 - 2 =:= sin(pi/2).
true.
3 - 2
计算结果为整数 1;然后,sin(pi/2)
求值为浮点数 1.0,这与整数 1 不统一。因此,第一个查询失败!
?- 1 = 1.0.
false.
我是 Prolog 的新手,所以请保持温柔。
这是我的规则:
solve(X) :- A = B, A is (7 * (X - 2)), B is (3 * (X + 4)).
显然,这里的正确答案是6.5
。如果我将其提供给 Prolog,它会确认:
| ?- solve(6.5).
yes
但是,如果我要求 Prolog 执行脏活,它会抛出错误:
| ?- solve(X).
uncaught exception: error(instantiation_error,(is)/2)
我完全承认这里发生的一切都是由于我对 Prolog 的误解。有人可以向我解释我如何使它起作用或为什么它不起作用吗?
在 Prolog 中,is
是算术求值运算符。它在右侧计算表达式的结果,并将其分配给左侧的变量。
要计算的表达式只能包含数字和算术 operators/functions。换句话说,要计算一个表达式,is
必须已经知道其中的所有数字。
另一种说法是 is
is "unidirectional",与双向的 =
不同。这是你所期望的。这就是你得到的错误的意思。
求解此类方程式 - 约束 - 是 constraint solver 的工作。
Prolog 通过统一工作。它试图使结构相同。
因此,例如,如果我尝试将 [3, X, 5]
与 [3, 4, 5]
统一,效果很好,而 X = 4
.
在你的代码中你首先说 A = B
。这很好,因为最初 A
和 B
没有被实例化,所以你基本上是将它们的命运联系在一起 - 如果 A
稍后被实例化,那么 B
也会自动实例化,或者签证-相反。
那你接着问A is (7 * (X - 2))
。现在,如果您已经将 X
与 6.5
统一,那么可以对其进行评估 - A
然后与 7 * (6.5 - 2)
或 31.5
统一。但是记住 A
已经和 B
统一了,所以 B
现在也是 31.5
.
现在你说B is (3 * (X + 4))
。因此 X
统一为 6.5
,B
统一为 31.5
这与 31.5 is (3 * (6.5 + 4))
相同。右边是 31.5
所以这是 31.5 is 31.5
这是真的。
所以,求解 solve(6.5)
是可行的。
但是,如果您尝试求解 X
,那么第一个谓词就可以正常工作。但是第二个没有。就像我问 "What's 7 times the number that is 2 less than the number I'm thinking of?" 除非我告诉你我在想的数字你不能给我答案。 Prolog 也一样。卡住报错
您可以为此使用库,至少在 SWI-Prolog 中可用:library(clpr) 和 library(clpq)。
这里来自雷亚尔的顶层:
?- use_module(library(clpr)).
true.
?- {7 * (X - 2) = 3 * (X + 4)}.
X = 6.5 ;
false.
或者,如果您使用 Rationals:
?- use_module(library(clpq)).
true.
?- {7 * (X - 2) = 3 * (X + 4)}, R is float(X).
X = 13 rdiv 2,
R = 6.5.
如果你想自己做,当然会多很多工作。您将不得不编写类似
的代码...,
( ground(X)
-> 7 * (X - 2) =:= 3 * (X + 4)
; X is (3*4 + 2*7) / (7 - 3)
),
...
顺便说一句,你在做什么:A = B, A is ..., B is ...
。
这个有点危险,例如:
?- A = B, A is 3 - 2, B is sin(pi/2).
false.
?- 3 - 2 =:= sin(pi/2).
true.
3 - 2
计算结果为整数 1;然后,sin(pi/2)
求值为浮点数 1.0,这与整数 1 不统一。因此,第一个查询失败!
?- 1 = 1.0.
false.