Prolog/数学、函数和等式
本节介绍如何在 prolog 中使用数学,使用函数和等式。
Prolog,像任何其他编程语言一样,对数字有表示。数字像常量一样使用,并像计算机上的任何地方一样表示,以下是谓词中处理数字的有效方式
a(12, 345). a(A) :- b(A, 234.3). a(345.3409857) :- b(23476.923804).
要对数字执行数学运算,我们需要函数。要将数学运算的结果存储在变量中,我们需要更仔细地查看等式。
到目前为止,谓词始终代表简单的真或假。谓词 a(A, B) 是真还是假,取决于 A 和 B 的值。函数是表示值的谓词。例如,sin() 谓词是一个函数。sin(0) 代表值 0,sin(1) 代表值 0.841471。函数可以在任何可以使用数字或常量的地方使用,在查询、谓词和规则中。例如,如果事实 p(0). 位于您的程序中,则查询 ?- p(sin(0)). 将与其统一。
以下常见的数学函数内置于大多数 Prolog 实现中
函数 | 示例 | 结果 |
---|---|---|
+ | 2 + 3 | 5 |
- | 36 - 5 | 31 |
* | 4 * 3 | 12 |
/ | 36/5 | 7.2 |
^ | 4 ^ 2 | 16 |
sin | sin(3) | 0.14112 |
(待补充表格)
请注意,函数本身无法计算。查询 ?- sin(3). 将失败,因为 sin() 被实现为函数而不是谓词。
函数和谓词之间的区别之一是,谓词的含义(或定义)通常由您自己定义,在您的程序中。当您使用 sin() 之类的函数时,它们已经在您的 prolog 实现中定义了。换句话说,prolog 不会在您的程序中找到定义,而是在其 内置 谓词库中找到。您可以创建自己的函数,但您通常不需要这样做。
有几种等式,含义略有不同。这里我们只看 = 运算符和 is 运算符。首先,看一下
?- A is 36/5.
此查询将数学运算 36/5 的结果分配给变量 A。因此 Prolog 将回答
A = 7.2
这个想法可能来自其他编程语言。然而,= 运算符非常不同。它不求解右侧,而是将其保留为公式。所以你会得到这个
?- A = 36/5. A = 36/5
Prolog 不会将运算的结果分配给变量 A,而是将运算分配给 A,而不进行求解。
您可以在查询中看到相同的情况。如果您询问
?- (31 is (36-5)).
您将得到“是”,因为 (36-5) 已被求解。但是,如果您询问
?- (31 = (36-5)).
您将得到“否”,因为 Prolog 会将数字 (31) 与公式 (36-5) 进行比较,而不是与求解公式的结果进行比较。
is 运算符专门用于数学函数。左操作数必须是变量,右操作数必须是所有变量都已实例化的数学函数。= 运算符用于变量的统一,并且可以用于任何两个操作数(尽管如果两个操作数不同,并且无法通过以特定方式实例化变量来使其相同,则它将失败)。
Prolog 知道许多其他比较两个项或实例化变量的方法,但就目前而言,这两个就足够了。在处理函数时,我们几乎总是使用 is 运算符。
现在我们已经了解了函数和等式,我们可以开始用数学进行编程。
plus(A, B, C) :- C is A + B.
此谓词将两个数字(A 和 B)相加,并将结果与 C 统一。以下程序稍微复杂一些。
fac(0,1). fac(A,B) :- A > 0, Ax is A - 1, fac(Ax,Bx), B is A * Bx.
此程序计算 A 的阶乘(数学表示法中的 A!)。
它递归地工作。第一条规则指出 0 的阶乘是 1。第二条规则指出,大于 0 的数字 A 的阶乘是 A-1 的阶乘乘以 A。
(1) Prolog 对以下查询(在空数据库上)将给出什么答案?尝试自己思考答案,然后使用 Prolog 编译器验证它。
- ?- X = 1 + 2 + 3.
- ?- X is 100/10.
- ?- X is (14 + 16)/3, X + 3 = Y.
- ?- X = 1000/100 + 5, Y is X.
(2) 编写一个名为 sigma 的谓词,使得当 N=A+(A+1)+(A+2)+...+(B-2)+(B-1)+B 时,sigma(A,B,N) 为真。换句话说,. 您可以假设 A 和 B 是整数,且 B>A。使用以下查询测试您的谓词
?- sigma(4,9,X). X = 39 ; fail. ?- sigma(-7,-2,X). X = -27 ; fail. ?- sigma(-5,5,X). X = 0 ; fail.
(3) 本章末尾显示的阶乘程序违反了使用递归规则的指南之一。在第二条规则中
fac(A,B) :- A > 0, Ax is A - 1, fac(Ax,Bx), B is A * Bx.
递归部分不是规则中的最后一个谓词。
- 展示 Prolog 如何评估查询 ?- fac(3, X). 并解释为什么程序如此设置。
- 解释为什么行 A > 0 是必要的。如果缺少该行,Prolog 在找到答案后会做什么?
(1) ?- X = 1 + 2 + 3.
X = 1 + 2 + 3. ?- X is 100/10. X = 10.
?- X is (14 + 16)/3, X + 3 = Y. X = 10. Y = 10 + 3.
?- X = 1000/100 + 5, Y is X. X = Y, Y = 15.
(2) 像往常一样,解决这个问题的方法不止一种。以下是一种与阶乘谓词类似地使用递归的方法。
sigma(A,A,A). sigma(A,B,N) :- B>A, %What do you think would happen if you removed this line? Try it. Why does this happen? A1 is A+1, sigma(A1,B,N1), N is A+N1.
尾递归方式:sigma(A,B,N):- add_1(A,B, A, N).
add_1(B,B,N,N).
add_1(A,B,Count,N):-
B > A, A1 is A + 1, Count1 is Count + A1, add_1(A1, B, Count1, N).