Prolog 中的谓词控制

Posted

技术标签:

【中文标题】Prolog 中的谓词控制【英文标题】:Predicate control in Prolog 【发布时间】:2011-05-06 03:03:35 【问题描述】:

对 Prolog 谓词控制有兴趣。

假设我有一个谓词 f(A,X) 和 g(B)。

f(A,X):- a,b,c, g(X).
g(B):- true.

a - returns true
b - returns true.
c - returns false.
where a,b and c are random predicates.

如果 c 返回 false,我如何继续评估谓词 f(A,X) 中的 g(X)

【问题讨论】:

【参考方案1】:

如果您的意图是定义f(A,X),以便无论c 是否失败,都应该评估g(X),那么:

    您可以使用蕴含 (->) 和/或析取 (;)、对其进行编码 f(A,X) 不需要根据c 定义。这假设c 没有副作用(例如,使用assert 断言数据库事实,或将IO 打印到流中)会改变环境并且在c 失败时无法撤消,在这种情况下,第一个选项更可取。

使用析取有几种替代方法,例如:

f(A,X) :- ((a, b, c) ; (a, b)), g(X).

这个定义(上面)根本不依赖于c,但它总是会执行c(只要ab成功)。如果 c 完全失败,则析取 (;) 允许 PROLOG 回溯以尝试执行 a, b 再次,并继续执行 g(X)。请注意,这相当于:

f(A,X) :- a, b, c, g(X).
f(A,X) :- a, b, g(X).

为了使 PROLOG 不会因为每次评估的第二个(相同的)头谓词 f(A,X) 而回溯两次评估 f(A,X),如果您的实现支持它,您可以选择放置一个剪切 (!) ,紧接在第一个子句中的c 子目标之后。剪切被放置在c 之后,因为如果c 失败,我们不希望解释器承诺f(A,X) 子句的选择,相反,我们希望解释器失败这个子句并尝试下一个子句,有效地忽略c并继续处理g(X)

另请注意,此解决方案依赖于没有副作用的ab,因为当c 失败时,ab 会再次执行。如果abc都有副作用,可以试试implication

f(A,X) :- a, b, (c -> g(X) ; g(X)).

无论c 是否失败,这也将始终有效地执行g(X),如果c 失败,则不会再次执行ab。这个单子句定义也不会像前面的建议那样留下选择点。

【讨论】:

【参考方案2】:

我猜你可以将c 包裹在ignore/1 中。考虑例如

?- false, writeln('Hello World!').
false.

?- ignore(false), writeln('Hello World!').
Hello World!
true.

但是,如果c 失败了,为什么还要继续呢?有什么用例?

我在 SWI-Prolog 中测试了这段代码,我不确定其他 Prolog 是否有 false/0ignore/1。 后者可以这样定义:

ignore(Goal) :- Goal, !.
ignore(_).

【讨论】:

+1 询问为什么这会有用。可移植的故障谓词是fail,顺便说一句。 (实现起来很简单:fail :- 0=1. 如果c 失败,您可能希望继续的一种情况是c副作用;有关详细信息,请参阅我对这个问题的回答。

以上是关于Prolog 中的谓词控制的主要内容,如果未能解决你的问题,请参考以下文章

Prolog 中的子列表谓词

如何阅读prolog中的谓词

Prolog:如何删除谓词中的对称值

覆盖 Prolog 中的预定义谓词

如何将用户输入转换为 gnu prolog 中的可重用谓词?

Prolog 中如何表示谓词逻辑?