Prolog中的谓词控制

Cri*_*ina 9 predicate prolog

对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.
Run Code Online (Sandbox Code Playgroud)

如果c返回false,我如何继续g(X)在谓词中进行求值f(A,X)

sha*_*rky 10

如果你的目的是要确定f(A,X)这样g(X)应评估是否c出现故障,则:

  1. 您可以使用implication(->)和/或disjunction(;)或者对此进行编码
  2. f(A,X) 不需要定义 c.这假设c没有副作用(例如,使用assert或向流打印IO来断言数据库事实),这会改变环境,并且在失败时无法撤消c,在这种情况下,第一个选项更可取.

使用析取有几种选择,例如:

f(A,X) :- ((a, b, c) ; (a, b)), g(X).
Run Code Online (Sandbox Code Playgroud)

这个定义(上面)根本不依赖c,但它总是会执行c(只要a并且b成功).析取(;)允许PROLOG原路返回,试图执行a, b 一次,如果c失败可言,并继续到g(X).请注意,这相当于:

f(A,X) :- a, b, c, g(X).
f(A,X) :- a, b, g(X).
Run Code Online (Sandbox Code Playgroud)

为了使PROLOG不会f(A,X)因为f(A,X)每个评估的第二个(相同的)头部谓词而回溯评估两次,您可以选择在第一个子句中的子目标之后立即放置一个cut(!),如果您的实现支持它.之后放置剪切是因为我们不希望解释器在失败的情况下提交该子句的选择,相反,我们希望解释器失败,并尝试下一个,有效地忽略并继续处理.c cf(A,X)ccg(X)

另外请注意,此解决方案依赖于ab没有副作用,因为当c发生故障时,ab再次执行.如果全部a,b并且c有副作用,您可以尝试使用暗示:

f(A,X) :- a, b, (c -> g(X) ; g(X)).
Run Code Online (Sandbox Code Playgroud)

这也将有效地执行始终g(X)是否c失败与否,并不会执行a,并b再次,如果c失败.这个单子句定义也不会像以前的建议那样留下选择点.