以系统的方式报告*为什么*查询在 Prolog 中失败

Reporting *why* a query failed in Prolog in a systematic way

我正在 Prolog 中寻找可用于 return 为什么 一组谓词失败的方法、模式或内置功能,位于至少就数据库中的谓词而言。当用户在系统中提出查询时,我试图说的不仅仅是“那是错误的”。

例如,假设我有两个谓词。如果东西是蓝色的,blue/1 为真,如果东西是狗,dog/1 为真:

blue(X) :- ...
dog(X) :- ...

如果我向 Prolog 提出以下查询并且 foo 是一只狗,但不是蓝色的,Prolog 通常只是 return "false":

? blue(foo), dog(foo)
false.

我想要找出 为什么 谓词的合取不正确,即使它是带外调用,例如:

? getReasonForFailure(X)
X = not(blue(foo))

如果谓词必须以某种方式编写,我没意见,我只是在寻找人们使用过的任何方法。

到目前为止,我这样做并取得了一些成功的方法是以程式化的方式编写谓词并使用一些辅助谓词来找出事后原因。例如:

blue(X) :-
    recordFailureReason(not(blue(X))),
    isBlue(X).

然后实现 recordFailureReason/1 以使其始终记住堆栈最深处发生的“原因”。如果查询失败,发生的最深的失败将被记录为失败的“最佳”原因。在许多情况下,这种启发式方法的效果出奇地好,但确实需要仔细构建谓词才能很好地工作。

有什么想法吗?如果有为这种分析设计的谓词逻辑系统,我愿意在 Prolog 之外寻找。

一些想法:

为什么逻辑程序会失败:“为什么”的答案当然是”,因为没有变量赋值满足由Prolog程序.

这显然毫无帮助,但这正是“蓝狗”的情况:没有这样的东西(至少在您建模的问题中)。

事实上,当系统进入完全 theorem-proving 模式并输出:

时,蓝狗问题的唯一可接受答案是获得的
blue(X) <=> ~dog(X)

或者只是

dog(X) => ~blue(X)

或者只是

blue(X) => ~dog(X)

取决于假设。 “没有蓝狗的证据”。这是真的,因为这就是程序的状态。所以这个问题中的一个“为什么”是要求重写程序...

可能 一个好的答案:“为什么没有 x 使得 x² < 0” 是 ill-posed 并且可能有答案 “只是因为”“因为你将自己限制在实数”“因为那等式中的 0 是错误的 ...所以这在很大程度上取决于。

为了使“为什么”更有帮助,您必须以某种方式限定这个“为什么”。这可以通过构建程序和扩展查询来完成,以便在证明树构建期间收集的额外信息冒泡,但你必须事先决定是什么信息:

query(Sought, [Info1, Info2, Info3])

并且此查询将始终成功(对于query/2,“成功”不再意味着“成功找到模型问题的解决方案”,而是“成功完成计算”),

变量 Sought 将是您想要回答的实际查询的具体答案,即原子之一 truefalse (如果您可能 unknown已经受够了 two-valued 逻辑)和 Info1, Info2, Info3 将提供额外的详细信息来帮助您回答 为什么某些东西 如果 Soughtfalse.

请注意,很多时候,问“为什么”的愿望归结为 mix-up 两种截然不同的失败:“未能找到模型问题的解决方案”和“未能完成”计算”。例如,您想将 maplist/3 应用于两个列表并期望它能工作,但错误地是两个列表的长度不同:您将得到 false - 但它将是 false 来自计算(在这种情况下,由于错误),而不是来自建模的 false。 heavy-handed 和 assertion/1 可能会有所帮助,但这以其自身的方式是丑陋的。

实际上,与命令式或函数式语言相比 w/o 逻辑编程部分:如果出现故障(也许是异常?),对应的“为什么”是什么?不清楚。

附录

这是一个很好的问题,但我对它的思考越多,我就越认为它只能以 task-specific 的方式回答:你必须将你的逻辑程序构建为 why-能够,并且您必须决定 why 实际上应该 return 什么样的信息。它 是一些东西 task-specific:关于缺失信息的东西,“如果只有这个或那个是真的”指示,其中“这个或那个”是从一组谓词中选择的.这当然是预料之中的,因为没有通用的方法可以让命令式或函数式程序解释它们的结果(或缺乏结果)。

我找了一些关于这方面的论文(包括 IEEE Xplore 和 ACM 图书馆),刚刚发现:

一定还有更多。

只要您保持在 Prolog 的纯单调子集中,您就可以将 概括 视为解释。以您的示例为例,根据您对 blue/1dog/1.

的精确定义,可能会想到以下概括
?- blue(foo), * dog(foo).
   false.

在此概括中,删除了整个目标 dog(foo)。前缀 * 实际上是一个定义为 :- op(950, fy, *). *(_). 的谓词 通俗地说,上面可以理解为:不仅这个查询失败了,甚至这个通用查询也失败了。根本没有蓝色的 foo(假设有 none)。 但也许 蓝色的 foo,但根本没有蓝色的狗......

?- blue(_X/*foo*/), dog(_X/*foo*/).
   false.

现在我们通过用新变量 _X 替换 foo 来概括程序。通过这种方式,两个目标之间的共享得以保留。

还有更多这样的概括可能,比如引入 dif/2

这项技术既可以手动应用,也可以自动应用。更多,有一个. Also see Declarative program development in Prolog with GUPU