prolog - Prolog 是否有像 Common Lisp 那样的条件和重启系统?

标签 prolog iso-prolog

Common Lisp 允许通过 conditions and restarts 进行异常处理。粗略地说,当函数抛出异常时,“捕获器”可以决定“抛出器”应如何/是否继续进行。 Prolog 提供类似的系统吗?如果没有,是否可以在现有谓词之上构建一个来遍历和检查调用堆栈?

最佳答案

ISO/IEC standard of Prolog仅提供了非常基本的异常和错误处理机制,或多或少与 Java 提供的机制相当,与 Common Lisp 的丰富机制相去甚远,但仍有一些值得注意的地方。特别是,除了实际的信令和处理机制之外,许多系统还提供类似于unwind-protect的机制。也就是说,即使存在未处理的信号,也能确保目标得到执行。

ISO throw /1, catch /3

使用 throw(Term) 引发/抛出异常。首先使用 copy_term/2 创建 Term 的副本,我们将其称为 Termcopy,然后使用此新副本来搜索相应的 catch(Goal, Pattern, Handler) 其第二个参数与 Termcopy 统一。当执行Handler时,所有由Goal引起的统一都被撤销。因此,Handler 无法访问执行 throw/1 时出现的替换。并且无法在执行 throw/1 的地方继续执行。

内置谓词的错误通过执行 throw(error(Error_term, Imp_def)) 发出信号,其中 Error_term 对应于 ISO's error classes 之一Imp_def 可以提供实现定义的额外信息(如源文件、行号等)。

在很多情况下,在本地处理错误会带来很大好处,但许多实现者认为实现起来太复杂。

让 Prolog 处理器在本地处理每个错误所需的额外工作量相当大,并且比 Common Lisp 或其他编程语言要大得多。这是由于 Prolog 中统一的本质。错误的本地处理需要撤消内置函数执行期间执行的统一:因此,实现者有两种实现此目的的可能性:

  • 在调用内置谓词时创建一个“选择点”,这会产生大量额外的开销,无论是创建此选择点还是“跟踪”后续绑定(bind)
  • 手动检查每个内置谓词,并根据具体情况决定如何处理错误 - 虽然这在运行时开销方面是最有效的,但也是成本最高且最容易出错的方法

利用内置程序中的 WAM 寄存器也会导致类似的复杂性。同样,人们可以选择缓慢的系统或具有大量实现开销的系统。

异常处理程序/3

然而,许多系统在内部提供了更好的机制,但很少有系统向程序员提供一致的机制。 IF/Prolog 提供了 exception_handler/3 ,其参数与 catch/3 相同,但在本地处理错误或异常:

[user] ?- catch((arg(a,f(1),_); Z=ok), error(type_error(_,_),_), fail).

no

[user] ?- exception_handler((arg(a,f(1),_); Z=ok), error(type_error(_,_),_), fail).

Z       = ok

yes

setup_call_cleanup/3

很多系统都提供了这个内置功能。它与 unwind-protect 非常相似,但由于 Prolog 的回溯机制,需要一些额外的复杂性。查看其 current definition .

<小时/>

所有这些机制都需要由系统实现者提供,它们不能构建在ISO Prolog之上。

关于prolog - Prolog 是否有像 Common Lisp 那样的条件和重启系统?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12629228/

相关文章:

prolog - 替换序言中的空格

algorithm - Prolog 练习 2-3-4 树

floating-point - PROLOG - 如何舍入 float 的小数?

prolog - Prolog 中的时间比较

prolog - Prolog 脚本的意外输出

prolog - 复杂抽象语法树的词序

prolog - SICStus Prolog 中的 current_predicate

prolog - 使用 clp(FD) 在 Prolog 中解决 4x4 乘法难题 "5040"

module - 为什么 prolog 的 ISO 模块标准失败了?

prolog - 序言中的“如果”?