正如其他人所指出的,Prolog 中的 谓词 之所以这样称呼是有原因的:它们实际上不是 函数。许多 Prolog 新手开始尝试将他们知道的其他语言的功能映射到 Prolog,但通常会失败。 Prolog 是一种与大多数其他语言非常不同的编程工具。所以这有点像用了很长时间的各种锤子,然后有人递给你一个扳手,你想知道为什么它不能成为一把好锤子。
在 Prolog 中,谓词 是一种在实体之间声明关系 的方法。如果您说foo(a, b),则表示a 和b 之间存在称为foo 的关系。您可能已经看过这些示例:knows(joe, jim). 和 knows(jim, sally). 您可以定义关系,例如:
remotely_acquainted(X, Y) :- knows(X, Z), knows(Z, Y), \+ knows(X, Y).
或者类似的东西。
谓词不返回值。它要么成功,要么失败。如果您有一系列用逗号分隔的谓词(“和”关系)并且Prolog遇到一个失败的谓词,它会备份(回溯)到最近的先前谓词,它可以通过其参数的不同实例化再次成功并移动再次前进。
为了增加一点混乱,Prolog 中有一些谓词是专门为计算算术表达式而设计的。这些行为类似于函数,但它们是特殊情况。例如:
X is Y / gcd(Z, 4).
这里,Z 和 4 中的 gcd 被计算并返回其值,然后 Y 除以该值并将结果实例化为 X。还有各种其他函数,如max/2、sin/1等,可以在文档中查找。
算术比较运算符也以这种方式运行(使用=:=/2、>/2、</2 等与数字表达式)。所以如果你说:
X < Y + Z
Prolog 将考虑对这些参数进行数值评估,然后对它们进行比较。
话虽如此,Prolog 确实允许嵌入术语结构。你可以有类似的东西:
car(cdr([1,2,3]))
作为一个术语。 Prolog 不会解释它。解释留给程序员。然后我可以创建一个谓词来定义这些术语的评估:
car([H|_], H).
cdr([_|T], T).
proc_list(car(X), Result) :-
proc_list(X, R1),
car(R1, Result), !.
proc_list(cdr(X), Result) :-
proc_list(X, R1),
cdr(R1, Result), !.
proc_list(X, X).
上述条款中的删减可防止在我不想要时回溯到proc_list(X, X)。
然后:
| ?- proc_list(car(cdr([1,2,3])), R).
R = 2
yes
| ?- proc_list(car(cdr(cdr([1,2,3]))), R).
R = 3
yes
| ?-
请注意,这是一个简单的案例,我可能没有掌握正确排列car 和cdr 的所有细节。也可以使用=.. 和call 等代替参数中的离散项car 和cdr 使其更通用。例如,更通用的proc_list 可能是:
proc_list(Term, Result) :-
Term =.. [Proc, X], % Assumes terms have just one argument
member(Proc, [car, cdr]), % True only on recognized terms
proc_list(X, R1), % Recursively process embedded term
ProcCall =.. [Proc, R1, Result], % Construct a calling term with Result
call(ProcCall), !.
proc_list(X, X).
这种处理术语的技术确实远离了 Prolog 最擅长的关系行为,并倾向于功能行为,但要了解 Prolog 的工作原理。