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/