我目前正在学习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
,如果两个参数相等,那当然是正确的。我也尝试使用\+
,但没有成功。
答案 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
我希望它会有用