Prolog 查找一个数字是否是另一个数字的倍数

Prolog 查找一个数字是否是另一个数字的倍数,prolog,failure-slice,successor-arithmetics,Prolog,Failure Slice,Successor Arithmetics,查看下面的代码: multiple(X,0). multiple(X,Y) :- lt(0,X), lt(0,Y), diff(Y,X,D), multiple(X,D). 碰巧出了什么事。供您参考: lt/2是第一个参数是否小于第二个参数。 diff/3是指第三个参数是否等于第一个参数减去第二个参数。 lt/2和diff/3定义正确 定义中是否存在逻辑错误?假设0是每个数字的倍数是有问题的还是逻辑错误在其他地方?我得到了正确的答案,但我认为这个问题进入了无限循环 编辑: 以下是其他定义 na

查看下面的代码:

multiple(X,0).
multiple(X,Y) :- lt(0,X), lt(0,Y), diff(Y,X,D), multiple(X,D).
碰巧出了什么事。供您参考:
lt/2是第一个参数是否小于第二个参数。
diff/3是指第三个参数是否等于第一个参数减去第二个参数。
lt/2和diff/3定义正确

定义中是否存在逻辑错误?假设0是每个数字的倍数是有问题的还是逻辑错误在其他地方?我得到了正确的答案,但我认为这个问题进入了无限循环

编辑:
以下是其他定义

natNum(0).
natNum(s(X)) :- natNum(X).

lt(0,s(X)) :- natNum(X).
lt(s(X),s(Y)) :- lt(X,Y).

sum(0,X,X).
sum(s(X),Y,s(Z)) :- sum(X,Y,Z).

diff(X,Y,Z) :- sum(Z,Y,X).

?- multiple(X, s(s(s(s(s(s(0))))))).

其中
s(0)
为1,
s(0))
为2等。它给出了X的所有所需答案,但在最后一个答案之后,它被卡住了。我假设在无限递归循环中

您的程序中发生了什么?它是永远循环,还是仅仅需要一段时间,因为你在最近几十年没有更新你的硬件?我们不知道。(实际上,我们可以通过查看您的程序来判断,但目前这太复杂了)

我们可以轻松地做的是缩小这一昂贵努力的来源。这一点,在没有深入了解你的计划的情况下。让我们从查询开始:

| ?- multiple(X, s(s(s(s(s(s(0))))))).
X = s(0) ? ;
X = s(s(0)) ? ;
X = s(s(s(0))) ? ;
X = s(s(s(s(s(s(0)))))) ? ;
** LOOPS or takes too long ***
难道没有更简单的方法吗?所有这些分号输入。相反,只需将
false
添加到查询中即可。通过这种方式,找到的解决方案将不再显示,我们可以集中精力处理这种恼人的循环。而且,如果我们做到了,您还可以将
false
目标添加到您的程序中!通过这样的目标,推论的数量可能会减少(或保持不变)。如果生成的片段(称为a)正在循环,那么这就是原始程序循环的原因:

multiple(_X,0) :- false. multiple(X,Y) :- lt(0,X), false, lt(0,Y), diff(Y,X,D), multiple(X,D). natNum(0) :- false. natNum(s(X)) :- natNum(X), false. lt(0,s(X)) :- natNum(X), false. lt(s(X),s(Y)) :- false, lt(X,Y). ?- multiple(X, s(s(s(s(s(s(0))))))), false. ** LOOPS *** 多个(X,0):-false。 多重(X,Y):-lt(0,X),false,lt(0,Y),diff(Y,X,D),多重(X,D)。 natNum(0):-false。 natNum(s(X)):-natNum(X),false。 lt(0,s(X)):-natNum(X),false。 lt(s(X),s(Y)):-false,lt(X,Y)。 -多个(X,s(s(s(s(s(0 ')))))),假。 **循环*** 你认识你的程序吗?只剩下循环所需的部分。实际上,在这种情况下,我们有一个无限循环

要解决这个问题,我们需要修改其余可见部分中的某些内容。我会选择
lt/2
,它的第一个子句可以推广到
lt(0,s())

但是等等!为什么可以把自然数的要求一概而论呢?查看您编写的事实
multiple(X,0)。
。您也没有要求
X
是一个自然数。这种过度概括通常出现在Prolog程序中。它们以相对较低的价格改进了终止属性:有时它们过于笼统,但所有附加到泛化中的术语都不是自然数。它们是类似于
any
[a,b,c]
的术语,因此如果它们出现在某个地方,您就知道它们不属于解决方案



因此,我们的想法是将
false
目标放入程序中,这样生成的程序(失败片段)仍然循环。在最坏的情况下,您将
false
放在错误的位置,程序将终止。通过反复试验,您可以获得最小的故障切片。所有这些现在被忽略的事情都是无关紧要的!特别是
diff/3
。因此(目前)不需要理解它。只需查看剩余的程序即可。

什么程序不起作用?什么查询失败了?您是否跟踪了。?
?-多个(X,s(s(s(s(s(s(s(s(0))是1,s(0))是2等)。它给出了X的所有所需答案,但在最后一个答案之后,它被卡住了。我假设在无限递归循环中@WillemVanon请添加
lt/2
diff/3
的定义。如果我们看不到他们,我们怎么知道呢!编辑:)@错误地写
X=s()
代替
lt(0,X)
(两次)我非常抱歉,但我无法理解。代码中潦草的部分是什么意思?为什么我们要在定义中添加
false
?这难道不会忽略所有这些定义吗?我很困惑。读一下,如果得到的片段。。。这就是问题所在:剩下的程序与您的原始程序有很大关系,因为这是其不终止的原因。您还想进一步解释什么吗?这难道不会忽略所有这些定义吗?是的,故障片不包含
diff/3
,因为问题已经独立于它而出现。