Prolog - 内置谓词


在Prolog中,我们在大多数情况下都看到了用户定义的谓词,但也有一些内置的谓词。内置谓词分为三种类型,如下所示 -

  • 识别术语

  • 分解结构

  • 收集所有解决方案

这是属于识别术语组的一些谓词的列表 -

谓词 描述
变量(X) 如果 X 当前是未实例化的变量,则成功。
诺瓦尔(X) 如果 X 不是变量或已实例化,则成功
Atomics(X) 如果 X 当前代表Atomics,则为 true
数量(X) 如果 X 当前代表数字,则为 true
整数(X) 如果 X 当前代表整数,则为 true
浮动(X) 如果 X 当前代表实数,则为 true。
Atomics(X) 如果 X 当前代表数字或Atomics,则为 true。
化合物(X) 如果 X 当前代表一个结构,则为 true。
接地(X) 如果 X 不包含任何未实例化的变量,则成功。

var(X) 谓词

当 X 未初始化时,则显示 true,否则显示 false。让我们看一个例子。

例子

| ?- var(X).

yes
| ?- X = 5, var(X).

no
| ?- var([X]).

no
| ?-

novar(X) 谓词

当X未初始化时,将显示false,否则显示true。让我们看一个例子。

例子

| ?- nonvar(X).

no
| ?- X = 5,nonvar(X).

X = 5

yes
| ?- nonvar([X]).

yes
| ?-

Atomics(X) 谓词

当带有 0 参数的非变量项和非数字项作为 X 传递时,这将返回 true,否则返回 false。

例子

| ?- atom(paul).

yes
| ?- X = paul,atom(X).

X = paul

yes
| ?- atom([]).

yes
| ?- atom([a,b]).

no
| ?-

数字(X) 谓词

这将返回 true,X 代表任意数字,否则返回 false。

例子

| ?- number(X).

no
| ?- X=5,number(X).

X = 5

yes
| ?- number(5.46).

yes
| ?-

整数(X) 谓词

当 X 是正整数值或负整数值时,这将返回 true,否则返回 false。

例子

| ?- integer(5).

yes
| ?- integer(5.46).

no
| ?-

float(X) 谓词

这将返回 true,X 是浮点数,否则返回 false。

例子

| ?- float(5).

no
| ?- float(5.46).

yes
| ?-

Atomics(X)谓词

我们有atom(X),它太具体了,它对于数字数据返回 false,atomic(X) 与atom(X) 类似,但它接受数字。

例子

| ?- atom(5).

no
| ?- atomic(5).

yes
| ?-

复合谓词(X)

如果atomic(X) 失败,则这些项要么是一个非实例化变量(可以使用var(X) 进行测试),要么是复合项。当我们传递一些复合结构时,复合将为真。

例子

| ?- compound([]).

no
| ?- compound([a]).

yes
| ?- compound(b(a)).

yes
| ?-

ground(X) 谓词

如果 X 不包含任何未实例化的变量,这将返回 true。这也会检查复合术语的内部,否则返回 false。

例子

| ?- ground(X).

no
| ?- ground(a(b,X)).

no
| ?- ground(a).

yes
| ?- ground([a,b,c]).

yes
| ?-

分解结构

现在我们将看到另一组内置谓词,即分解结构。我们之前已经看过识别术语。因此,当我们使用复合结构时,我们不能使用变量来检查或创建函子。它会返回错误。所以函子名称不能用变量表示。

错误

X = tree, Y = X(maple).
Syntax error Y=X<>(maple)

现在,让我们看看属于分解结构组的一些内置谓词。

函子(T,F,N) 谓词

如果 F 是 T 的主函子且 N 是 F 的元数,则返回 true。

注意- Arity 表示属性的数量。

例子

| ?- functor(t(f(X),a,T),Func,N).

Func = t
N = 3

(15 ms) yes
| ?-

arg(N,Term,A) 谓词

如果 A 是 Term 中的第 N 个参数,则返回 true。否则返回 false。

例子

| ?- arg(1,t(t(X),[]),A).

A = t(X)

yes
| ?- arg(2,t(t(X),[]),A).

A = []

yes
| ?-

现在,让我们看另一个例子。在此示例中,我们检查 D 的第一个参数为 12,第二个参数为 apr,第三个参数为 2020。

例子

| ?- functor(D,date,3), arg(1,D,12), arg(2,D,apr), arg(3,D,2020).

D = date(12,apr,2020)

yes
| ?-

../2 谓词

这是另一个用双点 (..) 表示的谓词。这需要 2 个参数,因此写为“/2”。所以 Term = .. L,如果 L 是一个包含 Term 函子及其参数的列表,则为真。

例子

| ?- f(a,b) =.. L.

L = [f,a,b]

yes
| ?- T =.. [is_blue,sam,today].

T = is_blue(sam,today)

yes
| ?-

通过将结构的组件表示为列表,可以在不知道函子名称的情况下递归处理它们。让我们看另一个例子 -

例子

| ?- f(2,3)=..[F,N|Y], N1 is N*3, L=..[F,N1|Y].

F = f
L = f(6,3)
N = 2
N1 = 6
Y = [3]

yes
| ?-

收集所有解决方案

现在让我们看看第三类,称为收集所有解决方案,它属于 Prolog 中的内置谓词。

我们已经看到,使用提示中的分号生成给定目标的所有给定解决方案。这是一个例子。

例子

| ?- member(X, [1,2,3,4]).

X = 1 ? ;

X = 2 ? ;

X = 3 ? ;

X = 4

yes

有时,我们需要在某些人工智能相关应用程序中生成某个程序中某个目标的所有解决方案。因此,三个内置谓词将帮助我们获得结果。这些谓词如下 -

  • 查找全部/3

  • 抵消/3

  • 巴戈夫/3

这三个谓词采用三个参数,因此我们在谓词名称后面写了“/3”。

这些也称为元谓词。这些用于操纵 Prolog 的证明策略。

句法

findall(X,P,L).
setof(X,P,L)
bagof(X,P,L)

这三个谓词表示满足目标 P 的所有对象 X 的列表(例如:age(X,Age))。它们都通过在 P 中实例化变量 X 并将其添加到列表 L 中来重复调用目标 P。当没有更多解决方案时,此过程就会停止。

Findall/3、Setof/3 和 Bagof/3

在这里,我们将看到三个不同的内置谓词 findall/3、setof/3 和 bagof/3,它们属于该类别,收集所有解决方案

findall/3 谓词

该谓词用于根据谓词 P 生成所有解 X 的列表。返回的列表将是 L。因此,我们将其读作“找到所有 X,使得 X 是谓词 P 的解,并将L 中的结果列表。这里这个谓词以 Prolog 找到它们的相同顺序存储结果。如果存在重复的解决方案,则所有解决方案都将进入结果列表,如果存在无限的解决方案,则该过程将永远不会终止。

现在我们也可以对它们做一些改进。第二个参数是目标,可能是一个复合目标。那么语法将是findall(X, (Predicate on X, other goal), L)

第一个参数也可以是任何复杂性的术语。那么让我们看看这几个规则的示例,并检查输出。

例子

| ?- findall(X, member(X, [1,2,3,4]), Results).

Results = [1,2,3,4]

yes
| ?- findall(X, (member(X, [1,2,3,4]), X > 2), Results).

Results = [3,4]

yes
| ?- findall(X/Y, (member(X,[1,2,3,4]), Y is X * X), Results).

Results = [1/1,2/4,3/9,4/16]

yes
| ?-

setof/3 谓词

setof/3 也类似于 findall/3,但这里它删除了所有重复的输出,并且答案将被排序。

如果目标中使用了任何变量,那么该变量将不会出现在第一个参数中,setof/3 将为该变量的每个可能的实例返回一个单独的结果。

让我们看一个例子来理解这个 setof/3。假设我们有一个如下所示的知识库 -

age(peter, 7).
age(ann, 5).
age(pat, 8).
age(tom, 5).
age(ann, 5).

这里我们可以看到age(ann, 5)在知识库中有两个条目。在这种情况下,年龄没有排序,名字也没有按字典顺序排序。现在让我们看一个 setof/3 用法的示例。

例子

| ?- setof(Child, age(Child,Age),Results).

Age = 5
Results = [ann,tom] ? ;

Age = 7
Results = [peter] ? ;

Age = 8
Results = [pat]

(16 ms) yes
| ?-

在这里我们可以看到年龄和名字都已排序。对于年龄 5,有两个条目,因此谓词创建了一个与年龄值对应的列表,其中包含两个元素。并且重复条目仅出现一次。

我们可以使用 setof/3 的嵌套调用来收集各个结果。我们将看到另一个示例,其中第一个参数是年龄/儿童。作为第二个参数,它将像以前一样需要另一组。所以这将返回(年龄/儿童)对的列表。让我们在序言执行中看到这一点 -

例子

| ?- setof(Age/Children, setof(Child,age(Child,Age), Children), AllResults).

AllResults = [5/[ann,tom],7/[peter],8/[pat]]

yes
| ?-

现在,如果我们不关心第一个参数中没有出现的变量,那么我们可以使用以下示例 -

例子

| ?- setof(Child, Age^age(Child,Age), Results).

Results = [ann,pat,peter,tom]

yes
| ?-

这里我们使用上面的插入符号 (^),这表明年龄不在第一个参数中。因此,我们将其读作“找到所有子项的集合,使得该子项具有年龄(无论它是什么),并将结果放入结果中”。

bagof/3 谓词

bagof/3 与 setof/3 类似,但这里它不会删除重复的输出,并且答案可能不会排序。

让我们看一个例子来理解这个 bagof/3。假设我们有一个知识库如下 -

知识库

age(peter, 7).
age(ann, 5).
age(pat, 8).
age(tom, 5).
age(ann, 5).

例子

| ?- bagof(Child, age(Child,Age),Results).

Age = 5
Results = [ann,tom,ann] ? ;

Age = 7
Results = [peter] ? ;

Age = 8
Results = [pat]

(15 ms) yes
| ?-

这里,对于 Age 值 5,结果为 [ann, tom, ann]。所以答案没有排序,重复的条目也没有删除,所以我们有两个“ann”值。

bagof/3 与 findall/3 不同,因为它为目标中未出现在第一个参数中的所有变量生成单独的结果。我们将使用下面的示例来了解这一点 -

例子

| ?- findall(Child, age(Child,Age),Results).

Results = [peter,ann,pat,tom,ann]

yes
| ?-

数学谓词

以下是数学谓词 -

谓词 描述
随机(L,H,X)。 获取 L 和 H 之间的随机值
之间(L,H,X)。 获取 L 和 H 之间的所有值
成功(X,Y)。 加 1 并将其分配给 X
绝对值(X)。 获取X的绝对值
最大(X,Y)。 获取 X 和 Y 之间的最大值
分钟(X,Y)。 获取 X 和 Y 之间的最小值
圆(X)。 舍入接近 X 的值
截断(X)。 将浮点数转换为整数,删除小数部分
地板(X)。 向下舍入
天花板(X)。 围捕
开方(X)。 平方根

除此之外,还有一些其他谓词,如 sin、cos、tan、asin、acos、atan、atan2、sinh、cosh、tanh、asinh、acosh、atanh、log、log10、exp、pi 等。

现在让我们使用 Prolog 程序来看看这些函数的实际效果。

例子

| ?- random(0,10,X).

X = 0

yes
| ?- random(0,10,X).

X = 5

yes
| ?- random(0,10,X).

X = 1

yes
| ?- between(0,10,X).

X = 0 ? a

X = 1

X = 2

X = 3

X = 4

X = 5

X = 6

X = 7

X = 8

X = 9

X = 10

(31 ms) yes
| ?- succ(2,X).

X = 3

yes
| ?- X is abs(-8).

X = 8

yes
| ?- X is max(10,5).

X = 10

yes
| ?- X is min(10,5).

X = 5

yes
| ?- X is round(10.56).

X = 11

yes
| ?- X is truncate(10.56).

X = 10

yes
| ?- X is floor(10.56).

X = 10

yes
| ?- X is ceiling(10.56).

X = 11

yes
| ?- X is sqrt(144).

X = 12.0

yes
| ?-