如果您的意图是定义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。这个单子句定义也不会像前面的建议那样留下选择点。