前言
Prolog内置了不少有用的谓词,得知一些,可以提升编程效率。《Programming In Prolog》(https://tieba.baidu.com/p/7964297542)的第6章总结了一些内置谓词,里面有几个我之前不怎么了解,读完后有一定收获。特别是第5节的内容,functor、=..等谓词甚至感觉有些元编程的味道。书中也提到了一些误区并进行了阐述,解答了我之前的一些困惑。我就在此把相关内容整理出来,但愿对后来人是有益的。如果只需要看最最基本的操作,可以看看之前写过的几篇教程:https://www.cnblogs.com/zhangoke/p/9510122.html。
当然,内置的有用的谓词不止这些,这个章节没有归纳操作列表等方面的一些谓词,后面有时间了再进行补充吧。
在电脑网页端,能正常显示加粗等格式,用电脑浏览此网页效果会更好一些。
1 导入新的子句
consult(X)
从文件中导入语句,如果有与现有谓词同名的谓词,会进行替换。如果文件名中含有“\”,前面需要再加上一个“\”,进行转义。
以列表形式导入
?- [file1,file2,’fred.1’,’bill.2’].
等同于
?- consult(file1), consult(file2), consult(’fred.1’), consult(’bill.2’).

2 成功与失败
true
其目标总是成功。这实际上是不必要的,因为子句和目标可以重新排序或重新组合,以避免使用true。然而,它的存在是为了方便。
fail
其目标总是失败。主要用在两个地方。一处是截断:。用来表示,“如果执行进行到这一步,那么可以放弃满足这一目标的尝试”。其形式为
…, !, fail.
另一处是,要明确要另一个目标回溯所有解决方案。你可能需要打印出所有解决方案。(但在我这边似乎没达到预期效果。)例如,
?- event(X, Y), phh(Y), fail.
3 界定项
var(X)
如果当前X是未实例化的变量,则var(X)成功。
nonvar(X)
如果当前X不是未实例化变量,则nonvar(X)成功。
atom(X)
如果当前X是Prolog的原子,则atom(X)成功。
number(X)
如果当前X代表一个数字,则number(X)成功。
atomic(X)
如果当前X是数字或原子,则atomic(X)成功。

4 把子句视为项
Prolog允许程序员检查和修改程序(用于满足目标的子句)。这特别简单,因为子句可以被看作是普通的Prolog结构。因此,Prolog提供了内置谓词,从而可以实现(但在我这边似乎有点问题):
likes(john, X) :- likes(X, wine)
等同于
’:-’(likes(john, X),likes(X, wine))
当规则中有多个目标时,这些目标被视为通过函子“,”(带两个参数)绑定在一起。
grandparent(X, Z) :- parent(X, Y), parent(Y, Z)
等同于
’:-’(grandparent(X, Z), ’,’(parent(X, Y), parent(Y, Z))
listing(A)
可以在大多数Prolog系统中检查当前已加载的子句。一种常见的方法是使用内置谓词listing,如果满足listing(A),其中A会被实例化为一个原子,所有以该原子为谓词的子句会被输出。
clause(X,Y)
满足clause(X,Y),X和Y会与数据库中现有子句(适用于“公共”谓词)的头部和主体相匹配。当要满足其目标时,必须充分实例化X,以便得知子句的主谓词。如果谓词没有子句,那么目标就会失败。例如:
?- clause(append(A, B, C), Y).
A = [],
B = C,
Y = true ;
A = [_A|_B],
C = [_A|_C],
Y = append(_B, B, _C).
asserta(X), assertz(X)
内置谓词asserta和assertz能用来向数据库添加新的子句(“动态”谓词)。这两个谓词的作用完全相同,只是asserta在数据库的开头添加子句,而assertz在结尾添加子句。
retract(X)
内置谓词retract能用来从数据库中删除子句(“动态”谓词)。其项必须被充分实例化,明确子句的谓词(就像asserta、clause等)。当满足时,会删除匹配的第1个语句。

5 构造和访问结构成分
functor(T, F, N)
谓词functor的语法为functor(T,F,N),表示T为一个有着函子F和参数数量为N的结构。例:
?- functor(f(a, b, g(Z)), F, N).
Z = _23, F = f, N = 3
?- functor(a + b, F, N).
F = +, N = 2
?- functor([a, b, c], F, N).
F = ., N = 2
?- functor(apple, F, N).
F = apple, N = 0
?- functor([a, b, c], ’.’, 3).
no
?- functor([a, b, c], a, Z).
no
它也可以用来构造结构,例如,复制一个现有结构:
copy(Old, New) :- functor(Old, F, N), functor(New, F, N).
arg(N,T,A)
谓词arg在使用时必须要有其前两个参数。它用于访问结构的特定参数。第一个参数指定需要第几个参数,第二个指定被查找的结构,第三个则与寻找到的参数进行匹配。也说是说,如果T的第N个参数为A。例:
?- arg(2, related(john, mother(jane)), X).
X = mother(jane)
?- arg(1, a+(b+c), X).
X=a
?- arg(2, [a,b,c], X).
X = [b,c]
?- arg(1, a+(b+c), b).
no
X =.. L
可以用functor和arg谓词创造和访问任意结构的参数。谓词“=..”提供了另一种方法。如果你想一次获得结构的参数,或者通过参数列表构建一个结构,这方法非常有用。L是由X的函子和X的参数组成的列表。例:
?- foo(a,b,c) =.. X.
X = [foo,a,b,c]
?- append([A|B], C, [A|D]) =.. L.
A = _2, B = _3, C = _4, D = _5,L = [append, [_2|_3], _4, [_2|_5]]
?- [a,b,c,d] =.. L.
L = [’.’,a,[b,c,d]].
?- (a+b) =.. L.
L = [+,a,b].
?- (a+b) =.. [+,X,Y].
X = a, Y = b.
?- [a,b,c,d] =.. [X|Y].
X = ’.’, Y = [a,[b,c,d]]
?- X =.. [a,b,c,d].
X = a(b,c,d).
?- X =.. [append,[a,b],[c],[a,b,c]].
X = append([a,b],[c],[a,b,c])
atom_chars(A,L)
谓词atom_chars将一个原子与组成它的字符列表相关联。这可以用于查找给定原子的字符,也可以用于查找具有某些给定字符的原子。atom_chars(A, L)表示“原子A的字符是列表L的成员”。例:
?- atom_chars(apple, X).
X = [a,p,p,l,e]
?- atom_chars(X, [a,p,p,l,e]).
X = apple
number_chars(A,L)
该谓词与atom_chars类似,只是它应用于数字而非原子。请注意:
?- atom_chars(X, [’1’ ,’2’, ’3’]).
变量X将实例化为原子’123’。如果希望它是一个数字,则要用number_chars。例:
?- number_chars(123.5, X).
X = [’1’, ’2’, ’3’, ’.’, ’5’]
?- number_chars(X, [’1’, ’2’, ’3’]).
X = 123

6 干涉回溯
repeat
repeat谓词能够回溯无数次。
7 构造复合目标
X,Y
只有X和Y子句都成功,它才会成功。
X;Y
X或Y子句成功,它就会成功。
类似前面第4节讲到的,它也有类似的另一种写法,例:
person(X) :- (X=adam; X=eve; mother(X, Y)).
等同于
person(X) :- ’;’( X=adam, ’;’(X=eve, mother(X, Y)) )
call(X)
假设X被实例化为可以被解释为目标的项。如果满足X的尝试成功,则call(X)目标成功。如果满足X的尝试失败,则call(X)目标失败。乍一看,这个谓词似乎是多余的。例如:
…, call(member(a, X)),…
总是可以换为
…, member(a, X),…
然而,如果通过“=..”、functor或arg构造目标,那么可以用call调用其中的未知函子的目标。例:
…, Z =.. [P,X,Y], call(Z),…
\+ X
如果满足X的尝试失败,则\+X目标成功。如果满足X的尝试成功,则\+X目标失败。
但需要注意:
?- member(X, [a,b,c]), write(X).
和
?- \+ \+ member(X, [a,b,c]), write(X).
是有一定差别的,前者会输出a;而后者输出的变量会未实例化。
后者在试图满足里层的\+目标会失败,因为member目标会成功。现在请记住,当目标失败时,任何实例化的变量(例如示例中的X)必须要“忘记”它们所代表的含义。因此,X变为非实例化的。在满足外层的\+目标,它会成功,因为其中的\+目标语句失败了。但这里的X仍未实例化。
8 等式
X=Y
试图通过将X和Y匹配在一起来使它们相等。
X == Y
谓词“==”表示比“=”更严格的等式检验。也就是说,如果X==Y成功,那么X=Y也会成功。但反之却并非如此。“==”更严格的地方是它考虑变量的方式。“=”谓词会将未实例化变量等同于任何值,因为它将匹配任何值;但“==”则需要一个未实例化变量与另一个已与其共享的未实例化变量相等。否则失败。例:
?- X == Y.
no
?- X == X.
X = _23
?- X=Y, X==Y.
X = _23, Y = _23
?- append([A|B], C) == append(X, Y).
no
?- append([A|B], C) == append([A|B], C).
A = _23, B = _24, C = _25

9 输入和输出
get_char(X)
如果X与当前输入流中的下一个字符一致,则此目标语句成功。get_char仅成功一次(无法再次满足)。在回溯时,移动到下一个字符的操作不会撤消,因为无法将字符放回当前输入流。
read(X)
该目标语句从当前输入流中读取下一个项,并将其与X匹配。其读取仅成功一次。读取的项后面必须跟一个点“.”,它不会成为项的一部分,并且至少有一个非打印字符。最后会从当前输入流中删除该点。
put_char(X)
此目标语句将字符X写入当前输出流。put_char只成功一次。如果X未实例化,则会发生错误。
nl
另起一行。nl只成功一次。
write(X)
此目标语句将项X写入当前输出流。写入仅成功一次。X中的任何未实例化变量都被写成以下划线开头的唯一编号变量,例如“_239”。要写入的同一共同引用变量在输出时具有相同的编号。
write_canonical(X)
谓词write_canonical的工作方式与write完全相同,只是它会忽略任何运算符声明。当使用write_canonical时,任何结构都会打印出来,首先是函子,然后是括号中的参数。
op(X, Y, Z)
该目标语句声明了一个具有优先类X、位置和关联性Y和名称Z的运算符。位置和关联度指定来自以下原子集合:
fx fy xf yf xfx xfy yfx yfy
如果运算符声明合法,那么op将成功。

10 操作文件
open(X, Y, Z)
打开一个名为X的文件。如果Y为read,则打开文件进行读取;如果Y为write,则打开文件进行写入。Z被实例化为一个特殊项,用于命名稍后访问文件时必须引用的流。
close(X)
当X是流的名称时,使用此选项。流在关闭后,无法再使用。
set_input(X)
将当前输入设置为以X为名的流。X将是open的第三个参数或原子user_input中返回的项,该参数指定输入将来自键盘。
set_output(X)
将当前输出设置为以X为名的流。X将是open的第三个参数或原子user_output中返回的项,该参数会指定在计算机输出显示。
current_input(X)
如果当前输入流的名称与X一致,则此目标语句成功,否则失败。
current_output(X)
如果当前输出流的名称与X一致,则此目标语句成功,否则失败。
11 算术表达式
X is Y
Y必须实例化为算术表达式的结构。首先,对Y求值以得出一个数字。其结果与X匹配,根据匹配结果,目标语句成功或失败。
X+Y
加
X-Y
减
X*Y
乘
X/Y
浮点除法
X // Y
整除
X mod Y
取余
12 比较
X=Y
如第8节中描述的这个等式谓词,在两个数字相同时也会成功。然而,如果其中一个参数是变量,则这个谓词会让变量实例化,因为等式谓词会让两个参数一致。在许多数值计算中,这是不可取的。因此,Prolog专门为比较数字的相等和不相等提供了谓词。在以下所有谓词中,两个参数都必须实例化,否则会发生错误。使用这些谓词进行数值计算也可以使程序更高效地运行。
X =:= Y
数值相等
X =\=Y
数值不等
X<Y
小于
X>Y
大于
X >= Y
大于等于
X =< Y
小于等于
此外,Prolog还提供比较两项的谓词。通常项比较运算符仅用于比较同类型的项,但也能比较其他组合。
所有未实例化的变量都小于所有浮点数,浮点数小于所有整数,整数小于所有原子,原子小于所有结构。
对于两个非共享的未实例化变量,其中一个将小于另一个(哪个更少在不同的Prolog实现中可能不同)。
在这种比较下,两个浮点数中,数值小的更小;两个整数中,数值小的更小。
如果一个原子在正常的词典顺序中比另一个原子排在前面,那么它就比另一个原子小。准确地说,顺序取决于字符代码,至少对于字母字符是这样。
一个结构比另一个结构的元数小,则这个结构会更小。如果两个结构具有相同的元数,则根据函子排序(使用原子的排序方法)。如果两个结构具有相同的元数和函子,则通过依次对参数进行判断来排列它们——对于第一个不同的对应参数,相关参数的顺序就是结构的顺序。
X @< Y
按照上述顺序排列,左边小于右边
X @> Y
按照上述顺序排列,左边大于右边
X @>= Y
按照上述顺序排列,左边大于等于右边
X @=< Y
按照上述顺序排列,左边小于等于右边

13 监视Prolog的运行
trace
启用穷举追踪。
notrace
停止穷举追踪。
spy P
可以使用谓词spy来关注某些特定谓词的目标。可以通过在它们上面设置监视点。这个谓词被定义为前缀操作符,因此不需要在参数周围加上括号。
debugging
内置谓词debugging可以用来查看当前设置了哪些监视点。
nodebug
nodebug会移除当前所有监视点。
nospy
像spy一样,nospy也是一个前缀运算符。Nospy比nodebug更具选择性,因为可以精确地指定希望删除的监视点。
Prolog内置了不少有用的谓词,得知一些,可以提升编程效率。《Programming In Prolog》(https://tieba.baidu.com/p/7964297542)的第6章总结了一些内置谓词,里面有几个我之前不怎么了解,读完后有一定收获。特别是第5节的内容,functor、=..等谓词甚至感觉有些元编程的味道。书中也提到了一些误区并进行了阐述,解答了我之前的一些困惑。我就在此把相关内容整理出来,但愿对后来人是有益的。如果只需要看最最基本的操作,可以看看之前写过的几篇教程:https://www.cnblogs.com/zhangoke/p/9510122.html。
当然,内置的有用的谓词不止这些,这个章节没有归纳操作列表等方面的一些谓词,后面有时间了再进行补充吧。
在电脑网页端,能正常显示加粗等格式,用电脑浏览此网页效果会更好一些。
1 导入新的子句
consult(X)
从文件中导入语句,如果有与现有谓词同名的谓词,会进行替换。如果文件名中含有“\”,前面需要再加上一个“\”,进行转义。
以列表形式导入
?- [file1,file2,’fred.1’,’bill.2’].
等同于
?- consult(file1), consult(file2), consult(’fred.1’), consult(’bill.2’).

2 成功与失败
true
其目标总是成功。这实际上是不必要的,因为子句和目标可以重新排序或重新组合,以避免使用true。然而,它的存在是为了方便。
fail
其目标总是失败。主要用在两个地方。一处是截断:。用来表示,“如果执行进行到这一步,那么可以放弃满足这一目标的尝试”。其形式为
…, !, fail.
另一处是,要明确要另一个目标回溯所有解决方案。你可能需要打印出所有解决方案。(但在我这边似乎没达到预期效果。)例如,
?- event(X, Y), phh(Y), fail.
3 界定项
var(X)
如果当前X是未实例化的变量,则var(X)成功。
nonvar(X)
如果当前X不是未实例化变量,则nonvar(X)成功。
atom(X)
如果当前X是Prolog的原子,则atom(X)成功。
number(X)
如果当前X代表一个数字,则number(X)成功。
atomic(X)
如果当前X是数字或原子,则atomic(X)成功。

4 把子句视为项
Prolog允许程序员检查和修改程序(用于满足目标的子句)。这特别简单,因为子句可以被看作是普通的Prolog结构。因此,Prolog提供了内置谓词,从而可以实现(但在我这边似乎有点问题):
likes(john, X) :- likes(X, wine)
等同于
’:-’(likes(john, X),likes(X, wine))
当规则中有多个目标时,这些目标被视为通过函子“,”(带两个参数)绑定在一起。
grandparent(X, Z) :- parent(X, Y), parent(Y, Z)
等同于
’:-’(grandparent(X, Z), ’,’(parent(X, Y), parent(Y, Z))
listing(A)
可以在大多数Prolog系统中检查当前已加载的子句。一种常见的方法是使用内置谓词listing,如果满足listing(A),其中A会被实例化为一个原子,所有以该原子为谓词的子句会被输出。
clause(X,Y)
满足clause(X,Y),X和Y会与数据库中现有子句(适用于“公共”谓词)的头部和主体相匹配。当要满足其目标时,必须充分实例化X,以便得知子句的主谓词。如果谓词没有子句,那么目标就会失败。例如:
?- clause(append(A, B, C), Y).
A = [],
B = C,
Y = true ;
A = [_A|_B],
C = [_A|_C],
Y = append(_B, B, _C).
asserta(X), assertz(X)
内置谓词asserta和assertz能用来向数据库添加新的子句(“动态”谓词)。这两个谓词的作用完全相同,只是asserta在数据库的开头添加子句,而assertz在结尾添加子句。
retract(X)
内置谓词retract能用来从数据库中删除子句(“动态”谓词)。其项必须被充分实例化,明确子句的谓词(就像asserta、clause等)。当满足时,会删除匹配的第1个语句。

5 构造和访问结构成分
functor(T, F, N)
谓词functor的语法为functor(T,F,N),表示T为一个有着函子F和参数数量为N的结构。例:
?- functor(f(a, b, g(Z)), F, N).
Z = _23, F = f, N = 3
?- functor(a + b, F, N).
F = +, N = 2
?- functor([a, b, c], F, N).
F = ., N = 2
?- functor(apple, F, N).
F = apple, N = 0
?- functor([a, b, c], ’.’, 3).
no
?- functor([a, b, c], a, Z).
no
它也可以用来构造结构,例如,复制一个现有结构:
copy(Old, New) :- functor(Old, F, N), functor(New, F, N).
arg(N,T,A)
谓词arg在使用时必须要有其前两个参数。它用于访问结构的特定参数。第一个参数指定需要第几个参数,第二个指定被查找的结构,第三个则与寻找到的参数进行匹配。也说是说,如果T的第N个参数为A。例:
?- arg(2, related(john, mother(jane)), X).
X = mother(jane)
?- arg(1, a+(b+c), X).
X=a
?- arg(2, [a,b,c], X).
X = [b,c]
?- arg(1, a+(b+c), b).
no
X =.. L
可以用functor和arg谓词创造和访问任意结构的参数。谓词“=..”提供了另一种方法。如果你想一次获得结构的参数,或者通过参数列表构建一个结构,这方法非常有用。L是由X的函子和X的参数组成的列表。例:
?- foo(a,b,c) =.. X.
X = [foo,a,b,c]
?- append([A|B], C, [A|D]) =.. L.
A = _2, B = _3, C = _4, D = _5,L = [append, [_2|_3], _4, [_2|_5]]
?- [a,b,c,d] =.. L.
L = [’.’,a,[b,c,d]].
?- (a+b) =.. L.
L = [+,a,b].
?- (a+b) =.. [+,X,Y].
X = a, Y = b.
?- [a,b,c,d] =.. [X|Y].
X = ’.’, Y = [a,[b,c,d]]
?- X =.. [a,b,c,d].
X = a(b,c,d).
?- X =.. [append,[a,b],[c],[a,b,c]].
X = append([a,b],[c],[a,b,c])
atom_chars(A,L)
谓词atom_chars将一个原子与组成它的字符列表相关联。这可以用于查找给定原子的字符,也可以用于查找具有某些给定字符的原子。atom_chars(A, L)表示“原子A的字符是列表L的成员”。例:
?- atom_chars(apple, X).
X = [a,p,p,l,e]
?- atom_chars(X, [a,p,p,l,e]).
X = apple
number_chars(A,L)
该谓词与atom_chars类似,只是它应用于数字而非原子。请注意:
?- atom_chars(X, [’1’ ,’2’, ’3’]).
变量X将实例化为原子’123’。如果希望它是一个数字,则要用number_chars。例:
?- number_chars(123.5, X).
X = [’1’, ’2’, ’3’, ’.’, ’5’]
?- number_chars(X, [’1’, ’2’, ’3’]).
X = 123

6 干涉回溯
repeat
repeat谓词能够回溯无数次。
7 构造复合目标
X,Y
只有X和Y子句都成功,它才会成功。
X;Y
X或Y子句成功,它就会成功。
类似前面第4节讲到的,它也有类似的另一种写法,例:
person(X) :- (X=adam; X=eve; mother(X, Y)).
等同于
person(X) :- ’;’( X=adam, ’;’(X=eve, mother(X, Y)) )
call(X)
假设X被实例化为可以被解释为目标的项。如果满足X的尝试成功,则call(X)目标成功。如果满足X的尝试失败,则call(X)目标失败。乍一看,这个谓词似乎是多余的。例如:
…, call(member(a, X)),…
总是可以换为
…, member(a, X),…
然而,如果通过“=..”、functor或arg构造目标,那么可以用call调用其中的未知函子的目标。例:
…, Z =.. [P,X,Y], call(Z),…
\+ X
如果满足X的尝试失败,则\+X目标成功。如果满足X的尝试成功,则\+X目标失败。
但需要注意:
?- member(X, [a,b,c]), write(X).
和
?- \+ \+ member(X, [a,b,c]), write(X).
是有一定差别的,前者会输出a;而后者输出的变量会未实例化。
后者在试图满足里层的\+目标会失败,因为member目标会成功。现在请记住,当目标失败时,任何实例化的变量(例如示例中的X)必须要“忘记”它们所代表的含义。因此,X变为非实例化的。在满足外层的\+目标,它会成功,因为其中的\+目标语句失败了。但这里的X仍未实例化。
8 等式
X=Y
试图通过将X和Y匹配在一起来使它们相等。
X == Y
谓词“==”表示比“=”更严格的等式检验。也就是说,如果X==Y成功,那么X=Y也会成功。但反之却并非如此。“==”更严格的地方是它考虑变量的方式。“=”谓词会将未实例化变量等同于任何值,因为它将匹配任何值;但“==”则需要一个未实例化变量与另一个已与其共享的未实例化变量相等。否则失败。例:
?- X == Y.
no
?- X == X.
X = _23
?- X=Y, X==Y.
X = _23, Y = _23
?- append([A|B], C) == append(X, Y).
no
?- append([A|B], C) == append([A|B], C).
A = _23, B = _24, C = _25

9 输入和输出
get_char(X)
如果X与当前输入流中的下一个字符一致,则此目标语句成功。get_char仅成功一次(无法再次满足)。在回溯时,移动到下一个字符的操作不会撤消,因为无法将字符放回当前输入流。
read(X)
该目标语句从当前输入流中读取下一个项,并将其与X匹配。其读取仅成功一次。读取的项后面必须跟一个点“.”,它不会成为项的一部分,并且至少有一个非打印字符。最后会从当前输入流中删除该点。
put_char(X)
此目标语句将字符X写入当前输出流。put_char只成功一次。如果X未实例化,则会发生错误。
nl
另起一行。nl只成功一次。
write(X)
此目标语句将项X写入当前输出流。写入仅成功一次。X中的任何未实例化变量都被写成以下划线开头的唯一编号变量,例如“_239”。要写入的同一共同引用变量在输出时具有相同的编号。
write_canonical(X)
谓词write_canonical的工作方式与write完全相同,只是它会忽略任何运算符声明。当使用write_canonical时,任何结构都会打印出来,首先是函子,然后是括号中的参数。
op(X, Y, Z)
该目标语句声明了一个具有优先类X、位置和关联性Y和名称Z的运算符。位置和关联度指定来自以下原子集合:
fx fy xf yf xfx xfy yfx yfy
如果运算符声明合法,那么op将成功。

10 操作文件
open(X, Y, Z)
打开一个名为X的文件。如果Y为read,则打开文件进行读取;如果Y为write,则打开文件进行写入。Z被实例化为一个特殊项,用于命名稍后访问文件时必须引用的流。
close(X)
当X是流的名称时,使用此选项。流在关闭后,无法再使用。
set_input(X)
将当前输入设置为以X为名的流。X将是open的第三个参数或原子user_input中返回的项,该参数指定输入将来自键盘。
set_output(X)
将当前输出设置为以X为名的流。X将是open的第三个参数或原子user_output中返回的项,该参数会指定在计算机输出显示。
current_input(X)
如果当前输入流的名称与X一致,则此目标语句成功,否则失败。
current_output(X)
如果当前输出流的名称与X一致,则此目标语句成功,否则失败。
11 算术表达式
X is Y
Y必须实例化为算术表达式的结构。首先,对Y求值以得出一个数字。其结果与X匹配,根据匹配结果,目标语句成功或失败。
X+Y
加
X-Y
减
X*Y
乘
X/Y
浮点除法
X // Y
整除
X mod Y
取余
12 比较
X=Y
如第8节中描述的这个等式谓词,在两个数字相同时也会成功。然而,如果其中一个参数是变量,则这个谓词会让变量实例化,因为等式谓词会让两个参数一致。在许多数值计算中,这是不可取的。因此,Prolog专门为比较数字的相等和不相等提供了谓词。在以下所有谓词中,两个参数都必须实例化,否则会发生错误。使用这些谓词进行数值计算也可以使程序更高效地运行。
X =:= Y
数值相等
X =\=Y
数值不等
X<Y
小于
X>Y
大于
X >= Y
大于等于
X =< Y
小于等于
此外,Prolog还提供比较两项的谓词。通常项比较运算符仅用于比较同类型的项,但也能比较其他组合。
所有未实例化的变量都小于所有浮点数,浮点数小于所有整数,整数小于所有原子,原子小于所有结构。
对于两个非共享的未实例化变量,其中一个将小于另一个(哪个更少在不同的Prolog实现中可能不同)。
在这种比较下,两个浮点数中,数值小的更小;两个整数中,数值小的更小。
如果一个原子在正常的词典顺序中比另一个原子排在前面,那么它就比另一个原子小。准确地说,顺序取决于字符代码,至少对于字母字符是这样。
一个结构比另一个结构的元数小,则这个结构会更小。如果两个结构具有相同的元数,则根据函子排序(使用原子的排序方法)。如果两个结构具有相同的元数和函子,则通过依次对参数进行判断来排列它们——对于第一个不同的对应参数,相关参数的顺序就是结构的顺序。
X @< Y
按照上述顺序排列,左边小于右边
X @> Y
按照上述顺序排列,左边大于右边
X @>= Y
按照上述顺序排列,左边大于等于右边
X @=< Y
按照上述顺序排列,左边小于等于右边

13 监视Prolog的运行
trace
启用穷举追踪。
notrace
停止穷举追踪。
spy P
可以使用谓词spy来关注某些特定谓词的目标。可以通过在它们上面设置监视点。这个谓词被定义为前缀操作符,因此不需要在参数周围加上括号。
debugging
内置谓词debugging可以用来查看当前设置了哪些监视点。
nodebug
nodebug会移除当前所有监视点。
nospy
像spy一样,nospy也是一个前缀运算符。Nospy比nodebug更具选择性,因为可以精确地指定希望删除的监视点。