如何停止回溯并结束Prolog中的递归

时间:2018-08-18 14:23:58

标签: prolog

我目前正在学习SWI-Prolog。我想实现一个函数factorable(X),如果X可以写成X = n*b.
,那么它是正确的 这是到目前为止我得到的:

isTeiler(X,Y) :- Y mod X =:= 0.

hatTeiler(X,X) :- fail,!.  
hatTeiler(X,Y) :- isTeiler(Y,X), !; Z is Y+1, hatTeiler(X,Z),!.

factorable(X) :- hatTeiler(X,2).

我的问题是,我现在不了解如何在不回溯的情况下以失败告终。我以为剪切会成功,但是在hatTeiler失败时两个参数相等时,它会直接跳到isTeiler,如果两个参数相等,那当然是正确的。我也尝试使用\+,但没有成功。

2 个答案:

答案 0 :(得分:1)

您看起来像是增加了削减以结束递归,但这通常是通过使规则标题更具体或为子句添加保护来实现的。

例如一条规则:

x_y_sum(X,succ(Y,1),succ(Z,1)) :-
  x_y_sum(X,Y,Z).

将永远不会与x_y_sum(X,0,Y)匹配。在这种情况下,递归就结束了。

或者,警卫将阻止对无效案件应用规则。

hatTeiler(X,X) :- fail,!.

我认为此规则应防止以下规则与相同参数的匹配。只需将X和Y的不等式添加为条件就容易得多了:

hatTeiler(X,Y) :-
  Y>X,
  isTeiler(Y,X),
  !;
  Z is Y+1,
  hatTeiler(X,Z),
  !.

然后hatTeiler(5,5)自动失败。 (*)

您还有一个析取运算符;,最好将其写为两个子句(我放弃了分界线,否则将无法探索所有可能性):

hatTeiler(X,Y) :- % (1)
  Y > X,
  isTeiler(Y,X).
hatTeiler(X,Y) :- % (2)
  Y > X,
  Z is Y+1,
  hatTeiler(X,Z).

现在我们可以声明性地阅读规则:

(1)如果Y大于X并且X将Y除以余数,则hatTeiler(X,Y)为true。 (2)如果Y大于X并且(大致而言)hatTeiler(X,Y + 1)为true,则hatTeiler(X,Y)也为true。

规则(1)听起来不错,但(2)听起来很腥:对于特定的X和Y,我们得到:hatTeiler(4,15)为true,而hatTeiler(4,16)为true。如果我正确理解,则此问题与除数有关,因此我不希望该属性保留。此外,序言的向后推理将尝试推导hatTeiler(4,17)hatTeiler(4,18)等,从而导致未终止。我猜您想让剪切停止递归,但看起来您需要其他属性。

从原始属性来看,您想检查X是否为N * B(对于某些N和B)。我们知道2 <= N <= X并且X mod N =0。对于第一个,甚至还有一个称为between/2,使整个过程变得两层:

hT(X,B) :-
   between(2, X, B),
   0 is (X mod B).


?- hT(12,X).
X = 2 ;
X = 3 ;
X = 4 ;
X = 6 ;
X = 12.

现在,您只需要编写自己的内容就可以了-一切都无需削减。

(*)更通用的hasTeiler(X,X)失败,因为is(和<)仅在右侧(两侧)无变量且仅包含算术项时才有效(即数字,+,-等)。

答案 1 :(得分:0)

如果您在失败之前进行剪切,则会冻结回溯。
如果prolog交叉,则cut操作将冻结回溯。
实际上,当序言失败时,它会回溯到上次剪切。
例如:

a:- b,
    c,!,
    d,
    e,!,
    f.

如果b或c失败,则回溯不会冻结。
如果d或f失败,则回溯立即冻结,因为在进行剪切之前
如果e失败了,它只能在d

上回溯

我希望它会有用