嗯,你快到了。由于您已经在这个问题上花费了相当长的时间,我将向您展示一些有效的代码并对其进行评论:
首先,我们调用一个工人谓词,它将携带X
和Y
作为参数并将它们初始化为0
:
validPair(Result) :-
validPair(0, 0, Result).
然后我们处理我们的基本情况。由于我们从 开始0
,基本情况是上限。我们本可以反过来,这只是一个选择。请注意,此处的剪切意味着我们不必担心在我们的以下子句Y
中优于,100
因为在这种情况下它们不会被执行。
validPair(_X, 101, []) :- !.
现在这是X
适合总和低于 的正确限制的情况100
。我们首先检查一切是否正常,然后我们使用!/0
谓词再次阻止执行到达我们的最后一个子句,因为那没有意义。完成后,我们只需 avec 计算有趣的值并将它们添加到列表中。
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 我将首先评论样式: 在此子句中(称为 fact,因为它没有正文),您只使用一次N
,X
即您不关心存储它们的值。在这种情况下,我们在他们的名字前面加上 a_
或者只使用匿名变量_
:
genList(100,N, X,[]).
变成
genList(100, _N, _X, []).
或者
genList(100, _, _, []).
同样的事情在这里S
。本条款中不使用它。它只在第一个中使用。您可以将其替换为_
或者_Sum
如果您也想在此处的其他条款中记录其使用(良好实践)。然后,您使用两个变量来保存完全相同的值。它在这里没有兴趣。只需将 next用作第一个参数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
只是 term +(N, X)
。这不是价值N + X
。您必须is/2
像在其他子句中一样使用谓词。与 for 的第二个子句相同的问题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).
由于它只是样式编辑,因此不会改变其行为。
现在让我们看看它有什么问题,不是在风格上,而是在逻辑上。首先,基本情况。这里一切都很好。你检查总和是你的上限,如果它是 return []
。完美的!
genList(100, _N, _X, []).
现在,您的“内部递归”。几乎没问题。让我们看看让我感到困扰的细节:您有一个值保留了之前的总和,但计算了一个新值并根据上限 + 1 重新测试它。更好的想法是测试PreviousSum
并< 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,[[X, Y, Sum, Product]|Xs]):-
PreviousSum < 100,
Y is N+1,
Sum is X + Y,
Product is X * Y,
genList(Sum, Y, X, Xs).
请注意,此修改有点风格,它不会修改程序行为。它仍然使它更具可读性!
现在,大灰狼:genList(_PreviousSum, N, X, Q) :- Sum 是 N + X,Sum < 101,NextX 是 X + 1,genList(0, NextX, NextX, Q)。这里有很多话要说。首先,再一次,您不需要计算Sum
,因为PreviousSum
已经持有该值。然后,应该测试它< 100
而不是< 101
. 然后,应该对其进行测试X >= N
,因为只有在这种情况下,您才不想通过第二个子句,而是在这个子句中。最后但并非最不重要的一点是,genList(0, NextX, NextX, Q)
您应该使用 genList(NextX, 0, NextX, Q) 开始它,而不是开始一个新的迭代。在这里,您没有正确重置值。结果子句是:
genList(PreviousSum, N, X, Q) :-
PreviousSum < 100,
N >= X,
NextX is X + 1,
genList(NextX, 0, NextX, Q).
正如你所看到的,我们知道我们不能通过我们的第二个子句 if 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).
变量命名仍然很差。更清晰的版本是:
genList(100, _X, _Y, []).
genList(PreviousSum, X, Y,[[X, Y, Sum, Product]|Xs]):-
PreviousSum < 100,
X < Y,
NewX is X + 1,
Sum is X + Y,
Product is X * Y,
genList(Sum, NewX, Y, Xs).
genList(PreviousSum, X, Y, Q) :-
PreviousSum < 100,
X >= Y,
NextY is Y + 1,
genList(NextY, 0, NextY, Q).
在这里您仍然有一个问题(是的,它永远不会结束:D):在计算总和产品等之前增加变量的事实意味着您跳过了一些值。之后尝试增加。让它作为练习:)