在ISO Prolog中没有捕获

Zby*_*ekZ 3 iso-prolog

我正在努力克服throw/1的精确语义,而没有ISO Prolog中合适的catch/3.我正在阅读ISO Prolog规范,在我看来,执行将以无限递归结束.

(请注意,您必须能够访问ISO Prolog标准才能解释此问题).

步骤1.假设我们调用throw(未知),并且堆栈上没有catch/3.

步骤2.它将在7.8.10.1 c)结束,说它将是一个系统错误(7.12.2 j).

第3步.这是在其他地方用于其他地方的同一种配方,所以我认为它应该以相同的方式解释.因此7.12.1适用,并且当前目标(throw/1)将被throw替换(error(system_error,Imp_def)).

步骤4.执行此目标将在堆栈上找不到活动的"catch".因此,它应该尝试相同的步骤,继续步骤2,依此类推=>无限递归.

你可能会说未被捕获的"throw"转换为system_error是"最终的"并且不会像其他错误一样进一步处理,并且它可能必须如此,以避免我描述的问题,但我的问题是,标准在哪里涵盖

其他一些注释,为了完整性:

  1. 7.12.2中的注4也提到了在这种情况下出现系统错误的可能性.我认为那里使用的公式("......没有活跃的目标捕获/ 3")在另一个方面引入了一些混淆,因为它应该符合条件,即捕手必须与错误术语统一(B ).

  2. 将未捕获的throw-s转换为系统错误背后的想法是什么?它看起来可能存在,使Prolog处理器的顶级生活"更容易",因此它只能收到一个可预测的错误?对我而言,这带来的问题多于好处 - 错误的真正原因因此消失 - 任何意见或评论?

  3. 形式语义(附件A)似乎也以某种方式与此斗争,尽管我没有详细研究它.在A.2.5,它提到,"...然而,在正式规范有在根捕手...",并且涉及它,例如,向的findall/3的执行.那么正式的规范与正文有何不同?

fal*_*lse 5

(我们在这里谈论ISO/IEC 13211-1:1995)

控制结构throw/1(7.8.10)的定义在两个地方说明,在这种情况下应该存在系统错误.首先,正如您所观察到的那样,有7.8.10.1 c:

c)如果S现在为
空,则应为系统错误(7.12.2 j),

然后,有错误条款:

7.8.10.3错误

a)B是一个变量
- instantiation_error.

b)B不与C任何调用
catch/3 的参数统一
- system_error.

要查看系统错误是什么,我们需要查看子条款7.12.2 j:

j)在
执行的任何阶段都可能存在系统错误.应该存在
系统错误的条件,以及
系统错误后处理器采取的操作是依赖于实现的.它有
形式system_error.

因此,系统错误后处理器采取的操作取决于实现.无限循环也没关系.

在符合标准的程序中,您不能依赖于该情况下的任何特定操作.

广告注1:注释不是规范性的.见1.1注释.它本质上是一个总结.

广告注释2:这是为了避免任何过度规范.这些部件在标准中尽可能保持模糊,因为系统错误可能损坏了Prolog系统.它与资源错误非常相似.理想情况下,系统会捕获它们并继续执行,但许多实现在一般情况下难以保证这一点.

广告注释3:形式语义是典型的另一种实现.在某些部分,实现必须做出某些决定,而规范可以留下所有可能性.除此之外,请注意形式语义不是规范性的.不过,它确实有助于调试标准.

编辑:在评论中你说:

(1mo)所以你说这允许处理器在发生系统错误时立即执行与实现相关的操作 - 不仅仅是在未被捕获之后?(2do)从而使其免于在7.12.1中应用目标转换的必要性?(3tio)如果系统错误无法捕获(通过catch/3),那么它也可以吗?

1MO

7.12.2 j中的句子

...系统错误后处理器采取的操作依赖于实现.

有效地否决了7.12.1.类似于7.12.2 h,也可能出现在"执行的任何阶段".

只是为了确保我们正确地阅读正确的代码假设相反.想象一下系统错误发生,7.12.1现在会产生这样一个没有被捕获的错误,然后我们又会出现系统错误等.因此:上面的句子永远不会适用.仅这一点就表明我们在这里读到的内容不正确.

另一方面,想象一下当系统完全损坏时发生系统错误的情况.现在应该如何执行7.12.1呢?所以Prolog系统将无法执行此循环.这是否意味着如果我们可以证明永远不会出现系统错误,Prolog处理器只能符合要求?这实际上是不可能的,特别是因为

7.12.2错误分类

笔记

...
4系统错误可能发生在例如(a)
与操作系统的交互中(例如,盘崩溃或中断),
......

如此有效,这意味着不能有任何符合Prolog的处理器.

2DO

7.12.1描述了在Prolog中处理错误的方法.也就是说,如果您能够在Prolog中处理错误,那么Prolog系统应该使用此方法.但是,在某些情况下,处理Prolog中的错误可能非常困难甚至不可能(见上述情况).在这种情况下,系统可能会纾困.

3tio

简短回答:是的.这是一个非常极端但有效的读数,系统错误无法捕获,执行将被终止.但也许,先退后一步,了解(a)技术标准是什么,不是什么,(b)标准的范围.

范围

或者,首先从b开始:在1范围内,我们有:

注 - ISO/IEC 13211的本部分未规定:

...
f)
Prolog处理器的用户环境(顶级循环,调试器,库系统,编辑器,编译器等).

(严格来说,这只是一个注释,但是如果你翻阅标准,你就会意识到这些方面没有指定.)我有点怀疑你真正想要的是理解顶级循环应该对未被捕获的错误做什么.但是,这个问题超出了13211-1的范围.报告此类错误并继续执行可能非常有意义.

目的

这里的另一点是技术标准实际上是什么.技术标准经常被误解为系统"正常"工作的完整保证.但是,如果系统符合技术标准,这并不意味着它适用于任何目的或用途.为了向您展示极端,请考虑shell命令exit 1,该命令可能被视为符合13211-1的处理器(前提是它附带了定义所有实现定义功能的文档).为什么?那么,当系统启动时,它可能意识到不满足最小要求(1范围,注b),因此它产生系统错误,通过产生错误代码1来处理.

你真正想要的是一个符合并且适合某些目的的系统(超出13211-1的范围).因此,除了询问自己某个行为是否符合要求之外,您还将了解该系统如何适合某些目的.

这方面的一个很好的例子是资源错误.许多Prolog系统能够处理某些资源错误.考虑:

p(-X) :- p(X).
Run Code Online (Sandbox Code Playgroud)

查询catch(p(X),error(E,_),true).系统现在有几个机会:无限循环(这需要一个非常非常智能的GC),成功E = resource_error(Resource),成功E = system_error,停止执行一些错误代码,占用所有资源.

虽然没有声明系统必须捕获这样的错误,但标准中提供了所有这些机制.

同样在a system_error:如果有意义的话,在Prolog中正确报告系统错误可能是一个好主意,但是,如果事情进展得太远,安全救助仍然不是最糟糕的事情.事实上,最糟糕的(但仍然是一致的)方式是继续执行"好像"一切都很好,但事实并非如此.