我很抱歉在此发布另一个问题,但我似乎只是在这里转圈!
对于我的程序,我需要列出一个列表,每个子列表包含2个数字,X和Y以及这两个数字的总和和乘积。 到目前为止,我有以下内容:
genList(100,N, X,[]).
genList(S,N, X,[[X,Y,Sum,Product]|Xs]):-
Y is N+1,
Sum is X+Y,
NewS is Sum,
Sum<101,
Product is X*Y,
N1 is N+1,
genList(NewS,N1, X,Xs).
genList(S,N,X,Q):-
N+X < 101,
NextX is X + 1,
genList(0,NextX,NextX,Q).
目标是找到总和<= 100的每对数字。因此,通过上面的一个起始值,X将找到每对1&lt; X&lt; Y,其中和<= 100,并且所有数字都是2-N,它将给出完整的可能对列表。
对于那些感兴趣的人,我正在解决的问题是总和/产品问题,描述为here(页面上的第二个)
如果有人可以提供帮助,我们将不胜感激!
此外,没有内置的prolog谓词可以使用,因此这样做的复杂方式而不是findall。
此谓词生成的小输出提取如下:
[[5,6,11,30],[5,7,12,35],[5,8,13,40],[5,9,14,45],[5,10,15 ,50],[5,11,16,55],[5,12,17,60],[5,13,18,65],[5,14,19,70],[5,15,20 ,75],[5,16,21,80],[5,17,22,85],[5,18,23,90],[5,19,24,95],[5,20,25,100 ],[5,21,26,105],[5,22,27,110],......
我认为它非常接近,但仍然有些不太正确。
它循环通过数字对,但需要使用“;”查看所有答案,这不是我想要的。此外,在所有答案都用完后,它返回false。我只是想不出来。
此外,它给出了起始值的完整答案,但每次都删除一个子列表,直到我只剩下最后一组对。
E.g。 genList(0,48,48,Q)。给了我:
[[48,49,97,2352],[48,50,98,2400],[48,51,99,2448],[48,52,100,2496]]
[[48,49,97,2352],[48,50,98,2400],[48,51,99,2448],[48,52,100,2496],[49,50,99,2450],[49,51,100,2499]]
[[48,49,97,2352],[48,50,98,2400],[48,51,99,2448],[49,50,99,2450],[49,51,100,2499]]
[[48,49,97,2352],[48,50,98,2400],[49,50,99,2450],[49,51,100,2499]]
[[48,49,97,2352],[49,50,99,2450],[49,51,100,2499]]
[[49,50,99,2450],[49,51,100,2499]]
false.
正如您所看到的,每次都会删除子列表,我只是看不清楚原因!
答案 0 :(得分:5)
首先,我们将工作者谓词称为X
和Y
作为参数并将其初始化为0
:
validPair(Result) :-
validPair(0, 0, Result).
然后我们处理我们的基本情况。由于我们从0
开始,基本情况是上限。我们本可以走另一条路,这只是一个选择。请注意,此处的缩减意味着我们不必担心Y
在以下条款中优于100
,因为在这种情况下它们不会被执行。
validPair(_X, 101, []) :- !.
现在,X
符合100
之和的正确限制。我们首先检查一切是否正常,然后我们使用!/0
谓词再次阻止执行到达我们的最后一个子句,因为那是没有意义的。完成后我们只需要计算有趣的值并将它们添加到列表中。
validPair(X, Y, [[X, Y, Sum, Product]|R]) :-
Limit is min(100 - Y, Y),
X =< Limit,
!,
Sum is X + Y,
Product is X * Y,
NextX is X + 1,
validPair(NextX, Y, R).
唯一需要处理的案例是当X
超过我们修正的限制时,总和低于100
。如果发生这种情况,我们会在下一个Y
重新开始,并将X
重置为0
。
validPair(_X, Y, R) :-
NextY is Y + 1,
validPair(0, NextY, R).
如果有任何问题,请在评论中要求澄清。
注意:这里使用的剪切是红色剪切 - 即谓词的正确性完全取决于子句的顺序。这是不好的做法。尝试用适当的防护装置补充它们(例如X =< 100
),这是一个很好的补充:)
现在让我们审核您的代码:D
我将从评论风格开始:
在这个子句中(称为事实,因为它没有正文),你只使用N
和X
一次,即你不关心存储它们的值。在这种情况下,我们使用_
为其名称添加前缀,或者只使用匿名变量_
:
genList(100,N, X,[]).
变成
genList(100, _N, _X, []).
或
genList(100, _, _, []).
S
与此相同。它没有在本节中使用。它仅用于第一个。如果您想在此处的其他条款中记录其使用,您可以将其替换为_
或_Sum
(良好做法)。然后,使用两个变量来保存完全相同的值。这里没兴趣。只需使用genList/4
作为第一个参数调用下一个Sum
,而不是仅为此声明一个新变量。与Y
和N1
相同。该条款的正确版本变为:
genList(S,N, X,[[X,Y,Sum,Product]|Xs]):-
Y is N+1,
Sum is X+Y,
NewS is Sum,
Sum<101,
Product is X*Y,
N1 is N+1,
genList(NewS,N1, X,Xs).
到
genList(_PreviousSum, N, X,[[X, Y, Sum, Product]|Xs]):-
Y is N+1,
Sum is X + Y,
Sum<101,
Product is X * Y,
genList(Sum, Y, X, Xs).
您的最后一个条款存在算术问题:N + X
只是术语+(N, X)
。它不是值N + X
。您必须像使用其他子句一样使用is/2
谓词。与S
的第二个条款相同的问题。那些小编辑转过来了:
genList(S,N,X,Q):-
N+X < 101,
NextX is X + 1,
genList(0,NextX,NextX,Q).
到
genList(_PreviousSum, N, X, Q) :-
Sum is N + X,
Sum < 101,
NextX is X + 1,
genList(0, NextX, NextX, Q).
所以,目前您的更正程序如下:
genList(100, _N, _X, []).
genList(_PreviousSum, N, X,[[X, Y, Sum, Product]|Xs]):-
Y is N+1,
Sum is X + Y,
Sum<101,
Product is X * Y,
genList(Sum, Y, X, Xs).
genList(_PreviousSum, N, X, Q) :-
Sum is N + X,
Sum < 101,
NextX is X + 1,
genList(0, NextX, NextX, Q).
由于它只是样式编辑,因此不会改变其行为。
现在让我们看一下它的错误,不是风格,而是逻辑。
一,基本情况。这里一切都很好。检查总和是否为上限,是否为返回[]
。完美!
genList(100, _N, _X, []).
现在,你的“内心递归”。它几乎很好。让我们看一下让我烦恼的细节:你有一个值可以保存你之前的总和,但计算一个新值并重新测试上限+ 1.更好的想法是测试PreviousSum
对{{1并删除< 100
测试。最好的理由是你有一个争论的事实!此外,更可以理解的是,在该限制情况下,它是用来防止执行该条款的。所以,
Sum < 101
会变成
genList(_PreviousSum, N, X,[[X, Y, Sum, Product]|Xs]):-
Y is N+1,
Sum is X + Y,
Sum<101,
Product is X * Y,
genList(Sum, Y, X, Xs).
请注意,此修改有点风格,它不会修改程序行为。它仍然使它更具可读性!
现在,大恶狼:
genList(_PreviousSum,N,X,Q): -
总和是N + X,
总和&lt; 101,
NextX是X + 1,
genList(0,NextX,NextX,Q)。
这里有很多话要说。首先,您不需要计算genList(PreviousSum, N, X,[[X, Y, Sum, Product]|Xs]):-
PreviousSum < 100,
Y is N+1,
Sum is X + Y,
Product is X * Y,
genList(Sum, Y, X, Xs).
,因为Sum
已经拥有该值。然后,应该测试PreviousSum
而不是< 100
。然后,它应该被测试< 101
,因为只有在那种情况下,你不想通过你的第二个条款而是在这个条款中。最后但并非最不重要的是,不应该使用X >= N
开始新的迭代,而应该使用genList(NextX,0,NextX,Q)启动它。这里没有正确重置值。结果条款是:
genList(0, NextX, NextX, Q)
如您所见,我们知道如果genList(PreviousSum, N, X, Q) :-
PreviousSum < 100,
N >= X,
NextX is X + 1,
genList(NextX, 0, NextX, Q).
我们无法通过我们的第二条款。我们应该加上适当的测试,以确保它是正确的:
N >= X
在这里你完成了,你的程序是正确的!
最终版本是:
genList(PreviousSum, N, X,[[X, Y, Sum, Product]|Xs]):-
PreviousSum < 100,
N < X,
Y is N+1,
Sum is X + Y,
Product is X * Y,
genList(Sum, Y, X, Xs).
变量命名仍然很差。更清晰的版本是:
genList(100, _N, _X, []).
genList(PreviousSum, N, X,[[X, Y, Sum, Product]|Xs]):-
PreviousSum < 100,
N < X,
Y is N+1,
Sum is X + Y,
Product is X * Y,
genList(Sum, Y, X, Xs).
genList(PreviousSum, N, X, Q) :-
PreviousSum < 100,
N >= X,
NextX is X + 1,
genList(NextX, 0, NextX, Q).
在这里你仍然有一个问题(是的,它结束了:D):在计算总和产品等之前增加变量的事实意味着你跳过一些值。尝试增加之后。这是一个练习:)