与序言列表建设更麻烦(More trouble with prolog list building)

2019-09-16 11:35发布

对不起张贴在此另一个问题,但我似乎在圈子怎么回事!

对于我的节目,我需要做一个列表的列表,包含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).

的目标是找到每对其中sum <= 100所以通过上述运行一个起始值的数字,X会发现每对1 <X <Y,其中sum <= 100,并通过将其与所有的数字2运行-N将给可能的对的完整列表。

对于那些有兴趣,我通过工作问题的总和/产品的问题,说明这里 (第二页上)

如果任何人都可以在这方面帮助将不胜感激!

此外,没有内置在序言谓词都能够被使用,因此这样做,而不是用的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。 我只是不明白。

此外,它给出了起始值一个完整的答案,但后来直到我只剩下最后一组对每次删除一个子表。

如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.

正如你所看到的,一个子表得到每次取出的,我只是不明白为什么!

Answer 1:

嗯,你几乎没有。 既然你花了相当长的一段时间对这个问题已经我就告诉你一些有效的代码和评论吧:

首先,我们称之为工人谓词会携带XY作为参数,并将其初始化为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和复位X0

validPair(_X, Y, R) :-
    NextY is Y + 1,
    validPair(0, NextY, R).

如果有什么麻烦请你要求澄清的意见。

注意:这里使用的裁员是削减红 - 即谓词的正确性完全取决于该条款的顺序。 这是不好的做法。 尝试用适当的防护,以补充他们(如X =< 100为例),它会是一个很好的补充:)

编辑:

现在,让我们审核您的代码:D我会通过评论风格开始:在本节中(称为事实,因为它没有正文),您使用NX只有一次,即你不关心存储自己的价值。 在这种情况下,我们的前缀名以_或只使用匿名变量_

genList(100,N, X,[]).

变成

genList(100, _N, _X, []).

要么

genList(100, _, _, []).

这里有同样的事情S 。 这不是这个子句中使用。 它仅在第一次使用。 您可以通过更换__Sum如果你想记录其这里的其他子句中使用过(好习惯)。 然后,您可以使用两个变量来保存的值完全相同。 它在这里有没有兴趣。 只需拨打你的下一个genList/4Sum作为第一个参数,而不是宣布一个新的变量只是这一点。 用同样的事情YN1 。 这一条款的正确的版本变成:

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< 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): - 总和为N + X,萨姆<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).

正如你看到的,我们知道形式化,我们无法通过我们如果第二句话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):你增加你的变量之前计算和积等意味着你跳过一些值的事实。 尝试后递增。 它让我们作为一个练习:)



文章来源: More trouble with prolog list building
标签: prolog