在SWI-Prolog的forall子句中使用成员是否总是以相同的顺序输出元素?

时间:2014-02-03 16:19:48

标签: prolog swi-prolog iso-prolog

最近进入Prolog我一直在使用它来执行一些简单的任务,并开始怀疑在forall循环中使用成员,如下面的简单例子中那样:

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网站上的功能文档非常简短。然而它确实提到了关于成员/ 2的确定性,它给了我一个暗示我可能正在说道它总是以相同的顺序提取元素,尽管我很不确定。

有人能给我任何保证或解释吗?

3 个答案:

答案 0 :(得分:4)

Prolog中的

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

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

关于forall/2的一个警示:一些Prolog定义了这个,但它可能没有你想象的那么有用,因为它实际上不是一个“循环”。您可以在示例中使用它,因为您只在每次迭代中执行打印副作用。对于大多数其他目的,您应该熟悉递归模式,如

print_list([]).
print_list([X|Xs]) :- print(X), print_list(Xs).

答案 1 :(得分:0)

N208具有forall / 2定义的+(call(Generator),+ call(Test)),因此这使其不太可疑。但是,由于ISO核心标准(+)/ 1已经进行了call / 1,并且ISO核心标准(,)/ 2将进行主体转换,因此可以在ISO核心标准Prolog中简单地将其定义如下:

  

forall(发生器,测试):-
  \ +(生成器,\ +测试)。

SWI-Prolog也以这种方式实现,并且在使用forall / 2时不会看到Ulrich Neumerkel观察到的错误:

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.

旁注:

我不知道它对循环有多大用处。在我看来,将其用于循环不是正确的方法,因为测试可能会失败,然后构造也会失败。我还通过Striegnitz and Blackburn看到了以下对helper的定义,谓谓它们称为故障驱动的循环。

  

doall(目标):-
  目标,失败。
  doall(_)。

我发现自己直接写了Goal, fail; true,也可以完成这项工作:

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.

答案 2 :(得分:-1)

严格来说,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/2中定义的forall(A,B)涵盖了您感兴趣的所有详细信息。 对于\+ (A, \+B)而言,编写forall/2更安全,因为这仅依赖于标准功能。没有\+ (A, \+B)这样的定义,因此很难说出“正确”行为是什么。

2do,SWI将符合标准。如果您阅读文档,您会注意到标准一致性没有自我声明(例如SICStus Prolog)。事实上,nonconforming并不完全符合,如下例中应该静默失败,而是打印?- \+ ( C= !, \+ (C,fail;writeq(nonconforming))).

{{1}}