Prolog 中的谓词控制 [英] Predicate control in Prolog
问题描述
对 Prolog 谓词控制有兴趣.
Have a curiosity related to Prolog predicate control.
假设我有一个谓词 f(A,X) 和 g(B).
Supposedly I have a predicate f(A,X) and 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)
?
How can I continue to evaluate g(X)
in the predicate f(A,X)
if c returns false?
推荐答案
如果你的意图是定义 f(A,X)
使得 g(X)
应该评估 c
是否失败,然后:
If your intention is to define f(A,X)
such that g(X)
should be evaluated whether or not c
fails, then either:
- 您可以使用蕴含 (
->
) 和/或析取 (;
)、或 f(A,X)
不需要用c
来定义.这假设c
没有副作用(例如,使用assert
断言数据库事实,或将 IO 打印到流中)会改变环境和c
失败时无法撤消,在这种情况下首选第一个选项.
- You could encode this using implication (
->
) and/or disjunction (;
), or f(A,X)
doesn't need to be defined in terms ofc
. This assumesc
has no side-effects (e.g., asserting database facts usingassert
, or printing IO to a stream) which alter the environment and which cannot be undone on failure ofc
, in which case the first option is preferable.
使用析取有几种替代方法,例如:
There are several alternatives for using disjunction, such as:
f(A,X) :- ((a, b, c) ; (a, b)), g(X).
这个定义(上图)根本不依赖于c
,但它总是会执行c
(只要a
和b
成功).如果 c
完全失败,则析取 (;
) 允许 PROLOG 回溯以尝试执行 a, b
again,并继续到 g(X)
.请注意,这相当于:
This definition (above) doesn't depend on c
at all, but it will always execute c
(as long as a
and b
succeed). The disjunction (;
) allows PROLOG to backtrack to try executing a, b
again if c
failed at all, and to continue onto g(X)
. Note that this is equivalent to:
f(A,X) :- a, b, c, g(X).
f(A,X) :- a, b, g(X).
为了让 PROLOG 不回溯两次评估 f(A,X)
因为第二个(相同的)头谓词 f(A,X)
对于每个评估,您可以选择放置一个剪切 (!
),如果您的实现支持它,紧跟第一个子句中的 c
子目标之后.剪切被放置在 c
之后,因为我们不希望解释器提交 f(A,X)
子句的选择 if c
失败了,相反,我们希望解释器在这个子句中失败并尝试下一个子句,有效地忽略 c
并继续处理 g(X)
.
In order for PROLOG not to backtrack to evaluate f(A,X)
twice because of the second (identical) head predicate f(A,X)
for every evaluation, you may choose to place a cut (!
), if your implementation supports it, immediately after the c
subgoal in the first clause. The cut is placed after c
because we don't want the interpreter to commit to that choice of f(A,X)
clause if c
had failed, instead, we want the interpreter to fail out of this clause and to try the next one, to effectively ignore c
and to continue processing g(X)
.
还要注意,这个解决方案依赖于没有副作用的 a
和 b
,因为当 c
失败时,a
和 b
再次执行.如果所有a
、b
、c
都有副作用,可以尝试使用implication:
Also note that this solution relies on a
and b
having no side-effects, because when c
fails, a
and b
are executed again. If all a
, b
, and c
have side effects, you can try using implication:
f(A,X) :- a, b, (c -> g(X) ; g(X)).
无论 c
是否失败,这也将始终有效地执行 g(X)
,并且不会执行 a
和 b如果
.这个单子句定义也不会像前面的建议那样留下选择点.c
失败,则再次
This will also effectively always execute g(X)
whether c
fails or not, and will not execute a
and b
again if c
fails. This single-clause definition will also not leave a choice-point like the previous suggestion.
这篇关于Prolog 中的谓词控制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!