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
(只要a
和b
成功)。如果 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)
。
另请注意,此解决方案依赖于没有副作用的a
和b
,因为当c
失败时,a
和b
会再次执行。如果a
、b
、c
都有副作用,可以试试implication:
f(A,X) :- a, b, (c -> g(X) ; g(X)).
无论c
是否失败,这也将始终有效地执行g(X)
,如果c
失败,则不会再次执行a
和b
。这个单子句定义也不会像前面的建议那样留下选择点。
【讨论】:
【参考方案2】:我猜你可以将c
包裹在ignore/1
中。考虑例如
?- false, writeln('Hello World!').
false.
?- ignore(false), writeln('Hello World!').
Hello World!
true.
但是,如果c
失败了,为什么还要继续呢?有什么用例?
我在 SWI-Prolog 中测试了这段代码,我不确定其他 Prolog 是否有 false/0
和 ignore/1
。
后者可以这样定义:
ignore(Goal) :- Goal, !.
ignore(_).
【讨论】:
+1 询问为什么这会有用。可移植的故障谓词是fail
,顺便说一句。 (实现起来很简单:fail :- 0=1.
)
如果c
失败,您可能希望继续的一种情况是c
有副作用;有关详细信息,请参阅我对这个问题的回答。以上是关于Prolog 中的谓词控制的主要内容,如果未能解决你的问题,请参考以下文章