2

我想编写一个递归到 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 的情况吗?

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

:- 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).
4

1 回答 1

2

跑步f(X,0),你X = a回来了。注意空白处。系统等待您的命令。

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

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

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

6 ?- f(X,0).
X = a ;
X = b.
%   ^^    no white space, no waiting, immediate termination.
于 2018-07-09T18:04:32.900 回答