如何避免整数基本情况的非终止?

How can I avoid nontermination with an integer base case?

我想写一个递归到 0 的谓词,但它总是无法终止。我使用故障切片将其缩小为:

f(a, 0).
f(b, 0).
f(X, Y) :- false.

当我将文件加载为 swipl -f test.pl 时,然后在提示中 运行 f(X, 0).,我得到输出 X = a 但我没有看到 X = b 或获得新提示。我希望它表现得像 A is 1 + 1,在那里我得到 A = 2. 和一个新的 ?- 提示符。

我可以用这样的东西让它工作,但它看起来不太干净:

f(X, 0) :- X = x.
f(X, Y) :- Y == 0 -> false; (NewY is Y - 1, f(X, NewY)).

对于列表,我可以将更一般的情况写成 f(X, [A|B]) 以确保它仅适用于列表至少有一个元素的情况。我可以做一些类似的事情来确保这里更一般的情况只适用于 Y 不为 0 的情况吗?

我看过 this question,虽然它暗示了正确的方向,但这也不起作用:

:- use_module(library(clpfd)).

int_int_prod(_, 0, 0).
int_int_prod(Num1, Num2, Result) :- 
    Num2 #> 0,
    NewNum2 #= Num2 - 1,
    int_int_prod(Num1, NewNum2, NewResult),
    Result #= Num1 + NewResult.

?- int_int_prod(0, 0, X).

运行 f(X,0),你得到 X = a 回来。注意白色 space。系统等待您的命令。

如果您在键盘上按 ;,它会响应 X = b。这是你不想发生的事情吗? (另一种选择是:按 .)。毕竟,您的定义确实为该查询提供 两个 解决方案,X=aX=b。为什么 Prolog 应该跳过第二个?不应该。

另一件事是,它仍然等待(在 SWI 中测试,通过 [user] 从提示加载)第二个结果后的用户响应。要删除 that,只需删除第三个子句。无论如何,这完全是多余的:明确失败与找不到更多匹配子句时失败的效果相同。

没有第三个子句 f(X,Y) :- false.,终止改进:

6 ?- f(X,0).
X = a ;
X = b.
%   ^^    no white space, no waiting, immediate termination.