Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/kubernetes/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在SWI Prolog的forall子句中使用member是否总是以相同的顺序输出元素?_Prolog_Swi Prolog_Iso Prolog - Fatal编程技术网

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

在SWI Prolog的forall子句中使用member是否总是以相同的顺序输出元素?,prolog,swi-prolog,iso-prolog,Prolog,Swi Prolog,Iso Prolog,最近进入Prolog之后,我已经将其用于一些简单的任务,并开始考虑在所有循环中使用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)). 从我最初所做的很少的研究来看,我猜想这可以归结为

最近进入Prolog之后,我已经将其用于一些简单的任务,并开始考虑在所有循环中使用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的决定论,这给了我一个线索,我可能在正确的道路上说,它总是以相同的顺序提取元素,尽管我还不确定


有人能就这一点向我提供任何保证或解释吗?

严格来说,SWI在几个层面上没有保证:

1mo,
member/2
forall/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
是在中定义的,它涵盖了您感兴趣的所有详细信息。 至于所有(A,B)的
更安全的做法是编写
\+(A,B)
,因为这只依赖于标准功能。对于all/2
本身没有定义,因此很难判断什么是“正确的”行为

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

?-  \+ ( C= !, \+ (C,fail;writeq(nonconforming))).
Prolog中的非决定论只是指一个谓词可能有多个解。显然,
member/2
就是这样一个谓词。这并不意味着您必须担心您的计算变得不可预测。Prolog有一个定义良好的计算规则,它本质上说,替代解决方案是以从左到右的方式进行深度探索的。因此,您的目标
成员(X[1,2,3,4])
将按预期顺序1,2,3,4生成
X
的解决方案

对列表[1,2,3,4]进行排序不会产生任何影响,因为它已经被排序(根据Prolog的标准术语顺序)

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

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

N208有forall/2定义的+(调用(生成器),+call(测试)),因此它不那么可疑。但由于ISO核心标准(+)/1已经调用了/1,并且ISO核心标准(,)/2将进行正文转换,因此可以在ISO核心标准序言中简单地对其进行如下定义:

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.
旁注:

我不知道它对循环有多有用。在我看来,将它用于循环不是正确的方法,因为测试可能会失败,然后构造也会失败。我还看到了一个助手谓词的定义,他们称之为failiure驱动循环

doall(目标):-
目标,失败。
道尔

我发现自己直接写了
目标,失败了;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.

我认为您可以依赖它,因为Prolog列表是单独链接的,任何其他遍历都会执行得更差。首先命名列表肯定没有任何语义差异。
forall/2
被定义为B-Prolog、BinProlog、CxProlog、GNU-Prolog、JIProlog、Lean-Prolog、LPA-WinProlog/MacProlog、Qu-Prolog、SWI-Prolog、XSB、YAP中的内置谓词。2009年10月的ISO Prolog核心修订提案草案中也对其进行了规定。在2009年第17次工作组会议上,投票赞成将其纳入本标准。似乎过了一段时间就掉了。但这并不排除将其视为事实上的标准谓词。@PauloMoura:除了GNU Prolog之外,您的列表中没有一个声明自己为ISO,这就为forall/2的定义留下了明确的含义。例如,YAP:
forall((fail,2),true)
成功,而不是产生错误。只有YAP上的顶层。在文件中定义的谓词子句的主体中编译相同的调用,会出现编译时错误。像这样的边缘情况,对于大多数使用场景来说,都不是问题。@PauloMoura:所以YAP不符合N208中的ISO+定义。它的行为也不一致。“Edge case”既不是ISO的概念,也不是N208的概念。这是一个SWI7错误,您的查询写入它。所以我想我应该再次投票。我首先误解了你的帖子。有趣的发现。在我的系统中运行良好,在ECLiPSe prolog中,在SICStus prolog中,等等…,all给出了正确的No.1 nice,这可能是OP在MindThank@jschimpf中所做的,现在更有意义了。同样感谢你关于递归的建议,这更多的是关于使用forall时会发生什么的理论问题,但我确实知道递归通常是一个更好的想法。这是不正确的,另见此。事实元组是确定性的,因为它在调用时总是返回相同的输出。成员是半确定性的,因为它为相同的输入提供相同的输出。非确定性意味着运行之间相同输入的潜在不同输出,如给定范围内的随机数生成。