The Prolog的ISO/IEC标准 https://stackoverflow.com/tags/iso-prolog/info仅提供了非常基本的异常和错误处理机制,或多或少与 Java 提供的机制相当,与 Common Lisp 的丰富机制相去甚远,但仍有一些值得注意的地方。特别是,除了实际的信令和处理机制之外,许多系统还提供类似于unwind-protect
。也就是说,即使存在未处理的信号,也能确保目标得到执行。
ISO 投掷/1,接球/3
引发/抛出异常throw(Term)
。首先是一份副本Term
是用创建的copy_term/2
让我们称之为Termcopy
然后这个新副本用于搜索相应的catch(Goal, Pattern, Handler)
其第二个参数与Termcopy
. When Handler
执行后,所有统一均由Goal
被撤销。所以没有办法Handler
访问出现的替换throw/1
被执行。并且没有办法在原来的地方继续下去throw/1
被处决。
内置谓词的错误通过执行来发出信号throw(error(Error_term, Imp_def))
where Error_term
对应于其中之一ISO 的错误类别 http://www.complang.tuwien.ac.at/ulrich/iso-prolog/error_k#error_classes and Imp_def
可以提供实现定义的额外信息(如源文件、行号等)。
在许多情况下,在本地处理错误会带来很大好处,但许多实现者认为它太复杂而难以实现。
让 Prolog 处理器在本地处理每个错误所需的额外工作量相当大,并且比 Common Lisp 或其他编程语言要大得多。这是由于 Prolog 中统一的本质。错误的本地处理需要撤消内置函数执行期间执行的统一:因此,实现者有两种实现此目的的可能性:
- 在调用内置谓词时创建一个“选择点”,这会产生大量额外的开销,无论是创建此选择点还是“尾随”后续绑定
- 手动检查每个内置谓词,并根据具体情况决定如何处理错误 - 虽然这在运行时开销方面是最有效的,但这也是成本最高且最容易出错的方法
利用内置程序中的 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 的回溯机制,需要一些额外的复杂性。见其当前定义 http://www.complang.tuwien.ac.at/ulrich/iso-prolog/cleanup.
所有这些机制都需要由系统实现者提供,它们不能构建在ISO Prolog之上。