prolog列表构建更麻烦

Xav*_*uos 2 prolog

很抱歉在这个问题上发布了另一个问题,但我似乎只是在这里转圈!

对于我的程序,我需要列出一个列表,每个子列表包含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).
Run Code Online (Sandbox Code Playgroud)

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

对于那些感兴趣的人,我正在解决的问题是和/产品问题,在这里描述(页面上的第二个)

如果有人可以帮助这一点,将不胜感激!

此外,没有内置的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.我只是想不出来.

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

例如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.
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,每次都会删除子列表,我只是看不清楚原因!

m09*_*m09 5

好吧,你快到了.既然你已经花了很长时间来解决这个问题,我只会向你展示一些有效的代码并对其进行评论:

首先,我们将一个worker谓词称为" 携带XY作为参数,并将它们初始化为0:

validPair(Result) :-
    validPair(0, 0, Result).
Run Code Online (Sandbox Code Playgroud)

然后我们处理我们的基础案例.从我们开始0,基本情况是上限.我们本可以走另一条路,这只是一个选择.请注意,这里的剪切意味着我们不必担心在以下条款中Y优于它们100,因为在这种情况下它们不会被执行.

validPair(_X, 101, []) :- !.
Run Code Online (Sandbox Code Playgroud)

现在是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).
Run Code Online (Sandbox Code Playgroud)

剩下要处理的唯一情况是X超过我们修正的限制,以便总和不足100.当发生这种情况时,我们再次使用下一个Y并重置X0.

validPair(_X, Y, R) :-
    NextY is Y + 1,
    validPair(0, NextY, R).
Run Code Online (Sandbox Code Playgroud)

如果有任何问题,请在评论中要求澄清.

注意:这里使用的剪切是红色剪切 - 即谓词的正确性完全取决于子句的顺序.这是不好的做法.尝试用适当的警卫补充它们(X =< 100例如),这是一个很好的补充:)

编辑:

现在,让我们审核您的代码:d我将通过评论风格开始:在本节中(称为事实,因为它没有主体),使用NX只有一次,即你不关心存储自己的价值.在这种情况下,我们在其名称前加上a _或只使用匿名变量_:

genList(100,N, X,[]).
Run Code Online (Sandbox Code Playgroud)

变成

genList(100, _N, _X, []).
Run Code Online (Sandbox Code Playgroud)

要么

genList(100, _, _, []).
Run Code Online (Sandbox Code Playgroud)

这跟同样的事情S.它没有在本节中使用.它仅用于第一个.您可以替换它,_或者_Sum如果您想在其他条款中记录它的使用(良好实践).然后,使用两个变量来保存完全相同的值.这里没兴趣.只需genList/4使用Sum第一个参数调用您的下一个,而不是仅为此声明一个新变量.同样的事情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).
Run Code Online (Sandbox Code Playgroud)

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).
Run Code Online (Sandbox Code Playgroud)

你的最后一个句子有算术问题: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).
Run Code Online (Sandbox Code Playgroud)

genList(_PreviousSum, N, X, Q) :-
    Sum is N + X,
    Sum < 101,
    NextX is X + 1,
    genList(0, NextX, NextX, Q).
Run Code Online (Sandbox Code Playgroud)

所以,目前您的更正程序如下:

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).
Run Code Online (Sandbox Code Playgroud)

由于它只是样式编辑,因此不会改变其行为.

现在让我们来看看它的错误,不是风格,而是逻辑.一,基本情况.这里一切都很好.检查总和是否为上限以及是否为返回值[].完善!

genList(100, _N, _X, []).
Run Code Online (Sandbox Code Playgroud)

现在,你的"内心递归".这几乎没问题.让我们来看看细节,困扰我:你有保存以前的总和值,但计算一个新的和重新测试它反对上限+ 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).
Run Code Online (Sandbox Code Playgroud)

会变成

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).
Run Code Online (Sandbox Code Playgroud)

请注意,此修改有点风格,它不会修改程序行为.它仍然使它更具可读性!

现在,大坏狼: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).
Run Code Online (Sandbox Code Playgroud)

如你所见,我们知道正式化我们不能通过我们的第二条款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).
Run Code Online (Sandbox Code Playgroud)

在这里你完成了,你的程序是正确的!

最终版本是:

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).
Run Code Online (Sandbox Code Playgroud)

变量命名仍然很差.更清晰的版本是:

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).
Run Code Online (Sandbox Code Playgroud)

在这里你仍然有一个问题(是的,它结束了:D):在计算总和产品等之前增加变量的事实意味着你跳过一些值.尝试增加之后.这是运动:)