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
成功).析取 (;
) 允许 PROLOG 回溯以尝试执行 a, b
again 如果 c
完全失败,并继续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
子目标.剪切位于 after 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屋!