6

最近进入 Prolog,我一直在使用它来完成一些简单的任务,并开始想知道如何在 forall 循环中使用 member,如下面的简单示例中的那个:

forall(member(A,[1,2,3,4]), print(A)).

在您执行此类操作的情况下,forall 是否总是会在每次调用时以相同的顺序处理列表中的元素?是否必须通过执行以下操作来强制执行:

A = [1,2,3,4], sort(A, B), forall(member(C,B), print(C)).

根据我最初所做的一些小研究,我猜测它归结为 member/2 的行为,但 SWI-Prolog 网站上的函数文档非常简短。然而,它确实提到了关于 member/2 的确定性,这给了我一个暗示,我可能在正确的道路上说它总是以相同的顺序提取元素,尽管我还不确定。

任何人都可以给我任何保证或解释吗?

4

3 回答 3

4

Prolog 中的非确定性只是指一个谓词可能有多个解决方案。显然,member/2就是这样一个谓词。这并不意味着您必须担心您的计算变得不可预测。Prolog 有一个定义明确的计算规则,它本质上说以深度优先、从左到右的方式探索替代解决方案。因此,您的目标member(X,[1,2,3,4])X按照预期的顺序 1、2、3、4 生成解决方案。

排序列表 [1,2,3,4] 不会有任何区别,因为它已经排序(根据 Prolog 的标准术语顺序)。

A word of caution about forall/2: some Prologs define this, but it is probably less useful than you imagine, because it is not really a "loop". You can use it in your example because you only perform a print side effect in each iteration. For most other purposes, you should familiarize yourself with recursive patterns like

print_list([]).
print_list([X|Xs]) :- print(X), print_list(Xs).
于 2014-02-04T19:16:14.920 回答
1

N208 has forall/2 defined + (call(Generator), + call(Test)), so this makes it less dubious. But by virtue that the ISO core standard (+)/1 does already a call/1 and that the ISO core standard (,)/2 will be subject to body conversion one can simply define it as follows in an ISO core standard Prolog:

forall(Generator, Test) :-
   \+ (Generator, \+ Test).

SWI-Prolog has also implemented this way, and the error observed by Ulrich Neumerkel will not be seen when using forall/2:

Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.18)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

?- \+ ( C= !, \+ (C,fail;writeq(nonconforming))).
nonconforming
true.

?- forall(C=!, (C,fail;writeq(nonconforming))).
false.

Side remark:

I don't know how useful it is for loop. It seems to me using it for loops is not the right approach, since the test might fail, and then the construct also fails. I have also seen by Striegnitz and Blackburn the following definition of a helper predicate that they call failiure driven loop.

doall(Goal) :-
   Goal, fail.
doall(_).

I find myself directly writing Goal, fail; true which also does the job:

Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.18)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

?- member(A,[1,2,3,4]), write(A), nl, fail; true.
1
2
3
4
true.
于 2018-07-25T07:33:16.750 回答
0

严格来说,SWI 在几个层面上并不能保证:

1mo,那member/2forall/2将以这种方式执行,因为您可以重新定义它们。

?- [user].
member(X,X).
|: % user://1 compiled 0.00 sec, 2 clauses
true.

?- forall(member(A,[1,2,3,4]), print(A)).
[1,2,3,4]
true.

但是,member/2Prolog 序言中定义,它涵盖了您感兴趣的所有细节。至于forall(A,B)编写更安全\+ (A, \+B),因为这仅依赖于标准功能。没有forall/2这样的定义,所以很难说什么是“正确的”行为。

2do,SWI 将符合标准。如果您阅读文档,您会注意到没有关于标准一致性的自我声明(例如 SICStus Prolog)。事实上,\+ (A, \+B)不完全符合,如下例所示,应该静默失败,而是打印nonconforming

?-  \+ ( C= !, \+ (C,fail;writeq(nonconforming))).
于 2014-02-03T16:48:10.707 回答