跳转到内容

Prolog/数学、函数和等式

来自维基教科书,开放世界中的开放书籍

本节介绍如何在 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).

上一个:列表 下一个:组合

华夏公益教科书