关于解决意外“未定义过程”错误的方法

时间:2017-02-26 11:53:58

标签: prolog

NB:为了清楚起见,我对以下问题的动机是学习Prolog和SWI-Prolog的方法,而不是通过特定的错误消息。事实上,我已经知道一种方法来克服这个错误。我的问题是关于其他几种替代方案是否也有可能。

我的Prolog教科书中的练习要求一个人描述一个人应该从几个查询中得到的结果,假设一个人事先咨询了以下知识库:

x(a).
z(b).
z(c).
z(d).
w(V) :- x(V).
w(V) :- y(V).
w(V) :- z(V).

至少在SWI-Prolog上,大多数查询都失败了,因为SWI-Prolog将y表示为未定义。

从本书最后的解决方案到练习,我可以看出这不是作者的预期结果。也许有一个Prolog实现,练习将随着解决方案的出现而转变。

尽管如此,我想了解解决问题的好方法。

例如,考虑查询w(x).。该书的解决方案声称查询w(x).应评估为false.。事实上,这就是:

?- w(x).
ERROR: w/1: Undefined procedure: y/1
   Exception: (7) y(x) ? 

(此时,SWI-Prolog希望我输入一些信,说明如何回应异常。稍后会详细介绍。)

我正在寻找将上述交互转为

的方法
?- w(x).
false.

?- 

...或者至少对于一个合适的<ONE-LETTER RESPONSE>我可以给SWI-Prolog,以便它到达结论false。我,所以

?- w(x).
ERROR: w/1: Undefined procedure: y/1
   Exception: (7) y(x) ? <ONE-LETTER RESPONSE>
false.

?- 

我至少知道一个问题的答案,即简单地删除或注释掉该行:

w(V) :- y(V).

我想知道其他可能的解决方案,例如我之前提到的“合适”。

另一种可能性是某些SWI-Prolog全局配置会导致上述交互变为

?- w(x).
false.

?- 

第三种可能性是以某种最小的方式“定义”y。我能提出的唯一方法是添加事实

y(dummy).

到知识库。是否有一种更简单的方法来定义y,这种方法不需要在话语领域引入无关的常量?

2 个答案:

答案 0 :(得分:4)

(这不是特定于SWI)

早在20世纪70年代,第一个Prolog系统实际上就像你描述的那样。很快就会发现这是错误的常见原因。简单的拼写错误很长时间未被发现。当前实现产生干净的存在错误。这是自1995年以来的标准行为。

但是,您可以使用ISO Prolog标志unknown返回旧的标记,其中包含三个值error(默认),failwarning。< / p>

?- inex.
ERROR: Undefined procedure: inex/0 (DWIM could not correct goal)
?- set_prolog_flag(unknown, fail).
Warning: Using a non-error value for unknown in the global module
Warning: causes most of the development environment to stop working.
Warning: Please use :- dynamic or limit usage of unknown to a module.
Warning: See http://www.swi-prolog.org/howto/database.html
true.

?- inex.
false.

?- set_prolog_flag(unknown, warning).
Warning: Using a non-error value for unknown in the global module
Warning: causes most of the development environment to stop working.
Warning: Please use :- dynamic or limit usage of unknown to a module.
Warning: See http://www.swi-prolog.org/howto/database.html
true.

?- inex.
Warning: toplevel: Undefined procedure: inex/0 (DWIM could not correct goal)
false.

正如您在上面所读到的,SWI建议改为使用dynamic声明 - 这反过来又有其自身的问题......相反,声明要好得多:

:- discontiguous(y/1).

答案 1 :(得分:1)

未定义的过程错误会引发异常,因此如果您希望引发异常,因为您不想更改y / 1谓词(删除或定义它),则需要捕获异常,然后返回false,如下所示:

x(a).
z(b).
z(c).
z(d).
w(V) :- x(V).
w(V) :- catch(y(V), error(Err,_Context),my_handler(Err)).
w(V) :- z(V).


my_handler(Err):- write(Err),fail.

示例:

?- w(x).
existence_error(procedure,y/1)
false.