Recursion 序言:将一个数字拆分成一系列递增的整数

Recursion 序言:将一个数字拆分成一系列递增的整数,recursion,prolog,Recursion,Prolog,在uni上做了一些Prolog并做了一些练习之后,我决定更进一步,尽管我不得不承认我不太理解递归,我得到了概念和想法,但如何编写它,对我来说仍然是一个问题。所以,这就是为什么我很好奇是否有人知道如何帮助解决这个问题 如果给想法一个数字,例如45,检查是否可以制作一个从1开始的列表,并将n+1加入列表,以及列表的总和是否与给定的数字相同 所以对于45,[1,2,3,4,5,6,7,8,9]是正确的 到目前为止,我试着查看Prolog中实现的[sum_list/2][1],但这只检查列表是否与后面的

在uni上做了一些Prolog并做了一些练习之后,我决定更进一步,尽管我不得不承认我不太理解递归,我得到了概念和想法,但如何编写它,对我来说仍然是一个问题。所以,这就是为什么我很好奇是否有人知道如何帮助解决这个问题

如果给想法一个数字,例如45,检查是否可以制作一个从1开始的列表,并将n+1加入列表,以及列表的总和是否与给定的数字相同

所以对于45,[1,2,3,4,5,6,7,8,9]是正确的

到目前为止,我试着查看Prolog中实现的[sum_list/2][1],但这只检查列表是否与后面的数字相同

给定一个谓词lijstSomL,S dutch表示listSum,给定

我的想法是这样的,例如,如果S=45,执行数字增加1减去S的步骤,如果0是余数,则返回列表,否则返回false

但对于这一点,您需要计数器,我发现在递归中很难理解这一点

编辑:

递归中的步骤

基本大小写空列表,0计数器个数,即减去S,45 S,余数

[1], 1, 44

[1,2], 2, 42

[1,2,3], 3, 39

我不知道如何阅读这个例子

?- lijstSom(L, 45)

L = [1,2,3,4,5,6,7,8,9],

False
…但可以将谓词lijstSomList,Sum看作是将某些整数列表与其和相关联,而不是计算整数列表的和。为什么要列出某些清单?因为我们有一个约束,整数列表中的整数必须从1开始,以1的增量单调递增

因此,您可以向Prolog处理器询问以下问题:

假设第一个参数是单调递增的整数列表,第二个参数是整数,那么说说lijstSom/2的第一个参数和第二个参数lijstSom/2之间的关系:

lijstSom[1,2,3],和

。。。应该返回true,因为是的,至少有一个解决方案,并给出Sum=6,因为它也构造了解决方案。。。我们就在这里的某个角落

lijstSomL,6岁

。。。应返回true,因为存在至少一个解决方案,并给出解决方案[1,2,3]

lijstSom[1,2,3],6

。。。应返回true,因为[1,2,3]的和为6;不需要进一步的资料

李斯特索姆,S

。。。如果一个无穷系列的真解和对解产生了解

L = [1], S = 1;
L = [1,2], S = 3;
L = [1,2,3], S = 6;
...
lijstSom[1,2,3],7

…应返回false fail,因为7与[1,2,3]的关系不是7=/=1+2+3

您甚至可能希望Prolog处理器能够讲述一些有趣的事情:

lijstSom[1,2,X],6

甚至

lijstSom[1,2,X],S

事实上,lijstSom/2在数学上尽可能接近物理上的神奇,也就是说:

可以不受限制地访问柏拉图数学空间中某个地方的列表和关系的完整表。 能够在不到无限的步骤中找到正确的条目。 然后输出它。 当然,出于非常实际的原因,我们仅限于低指数和有限数量的可识别符号的多项式算法。糟透了

因此,首先使用归纳定义定义lijstSomL,S:

lijstSom[最终值为N]的列表,S。。。如果。。。lijstSom[a列表]、S-N和 lijstSom[],0,因为空列表的总和为0。 这很好,因为它提供了将任意长度的列表最终缩减为大小为0的列表的方法,同时保留了全部知识的总和

Prolog不擅长处理列表的尾部,但擅长处理列表的头部,因此我们欺骗并更改了lijstSom/2的定义,以声明列表是按相反的顺序给出的:

lijstSom[3,2,1],6

现在是一些代码

=是与运算符相等的常数。要使用它,我们需要发布use_modulelibraryclpfd。先指挥

lijstSom([],0).
lijstSom([K|Rest],N) :- lijstSom([Rest],T), T+K #= N.
以上内容遵循lijstSom的数学要求,并允许Prolog处理器执行其计算:在第二个子句中,它可以从大小为a-1的列表的值计算大小为a的列表的值,从总是减少列表长度的阶梯上下降,直到到达lijstSom[],0的终止情况

但是我们没有提到任何关于单调递减1的列表。 让我们更准确地说:

lijstSom([],0) :- !.
lijstSom([1],1) :- ! .
lijstSom([K,V|Rest],N) :- K #= V+1, T+K #= N, lijstSom([V|Rest],T).
更好

我们还添加了“!”告诉Prolog处理器不要寻找超过这一点的替代解决方案,因为我们对算法的了解比以往任何时候都要多。另外,第三行是有效的,但这仅仅是因为我在运行下面的测试并通过测试后得到了它

如果检查失败,Prolog处理器将显示false-输入没有解决方案。这正是我们想要的

但它有效吗?在这台杰出的物理机器的数学性方面,我们能走多远

负载库CLPFD用于约束和单元测试:

蒲公英 t将其保存到文件x.pl中,您可以使用[x]别名“consult'x”加载该文件,或使用Prolog REPL上的make重新加载该文件:

:- use_module(library(clpfd)).

lijstSom([],0) :- 
   format("Hit case ([],0)\n"),!.
lijstSom([1],1) :-
   format("Hit case ([1],1)\n"),!.
lijstSom([K,V|Rest],N) :- 
   format("Called with K=~w, V=~w, Rest=~w, N=~w\n", [K,V,Rest,N]),
   K #= V+1, 
   T+K #= N,   
   T #> 0, V #> 0, % needed to avoid infinite descent
   lijstSom([V|Rest],T).

:- begin_tests(listsom).

test("0 verify") :- lijstSom([],0).
test("1 verify") :- lijstSom([1],1).
test("3 verify") :- lijstSom([2,1],3).
test("6 verify") :- lijstSom([3,2,1],6).

test("0 construct") :- lijstSom(L,0) , L = [].
test("1 construct") :- lijstSom(L,1) , L = [1].
test("3 construct") :- lijstSom(L,3) , L = [2,1].
test("6 construct") :- lijstSom(L,6) , L = [3,2,1]. 

test("0 sum") :- lijstSom([],S) , S = 0.
test("1 sum") :- lijstSom([1],S) , S = 1.
test("3 sum") :- lijstSom([2,1],S) , S = 3.
test("6 sum") :- lijstSom([3,2,1],S) , S = 6.

test("1 partial") :- lijstSom([X],1) , X = 1. 
test("3 partial") :- lijstSom([X,1],3) , X = 2. 
test("6 partial") :- lijstSom([X,2,1],6) , X = 3. 

test("1 extreme partial") :- lijstSom([X],S) , X = 1, S = 1.
test("3 extreme partial") :- lijstSom([X,1],S) , X = 2, S = 3.
test("6 extreme partial") :- lijstSom([X,2,1],S) , X = 3, S = 6.

test("6 partial list") :- lijstSom([X|L],6) , X = 3, L = [2,1]. 

% Important to test the NOPES

test("bad list", fail) :- lijstSom([3,1],_).
test("bad sum", fail) :- lijstSom([3,2,1],5).
test("reversed list", fail) :- lijstSom([1,2,3],6).
test("infinite descent from 2", fail) :- lijstSom(_,2).
test("infinite descent from 9", fail) :- lijstSom(_,9).

:- end_tests(listsom).
然后


你会怎么说?是的,他可能会因为什么事发牢骚。

我不知道怎么读这个例子

?- lijstSom(L, 45)

L = [1,2,3,4,5,6,7,8,9],

False
…但可以将谓词lijstSomList,Sum看作是将某些整数列表与其和相关联,而不是计算整数列表的和。为什么要列出某些清单?因为我们有一个约束,整数列表中的整数必须从1开始,以1的增量单调递增

因此,您可以向Prolog处理器询问以下问题:

假设第一个参数是单调递增的整数列表,第二个参数是整数,那么说说lijstSom/2的第一个参数和第二个参数lijstSom/2之间的关系:

lijstSom[1,2,3],和

。。。应该返回true,因为是的,至少有一个解决方案,并给出Sum=6,因为它也构造了解决方案。。。我们就在这里的某个角落

lijstSomL,6岁

。。。应返回true,因为存在至少一个解决方案,并给出解决方案[1,2,3]

lijstSom[1,2,3],6

。。。应返回true,因为[1,2,3]的和为6;不需要进一步的资料

李斯特索姆,S

。。。如果一个无穷系列的真解和对解产生了解

L = [1], S = 1;
L = [1,2], S = 3;
L = [1,2,3], S = 6;
...
lijstSom[1,2,3],7

…应返回false fail,因为7与[1,2,3]的关系不是7=/=1+2+3

您甚至可能希望Prolog处理器能够讲述一些有趣的事情:

lijstSom[1,2,X],6

甚至

lijstSom[1,2,X],S

事实上,lijstSom/2在数学上尽可能接近物理上的神奇,也就是说:

可以不受限制地访问柏拉图数学空间中某个地方的列表和关系的完整表。 能够在不到无限的步骤中找到正确的条目。 然后输出它。 当然,出于非常实际的原因,我们仅限于低指数和有限数量的可识别符号的多项式算法。糟透了

因此,首先使用归纳定义定义lijstSomL,S:

lijstSom[最终值为N]的列表,S。。。如果。。。lijstSom[a列表]、S-N和 lijstSom[],0,因为空列表的总和为0。 这很好,因为它提供了将任意长度的列表最终缩减为大小为0的列表的方法,同时保留了全部知识的总和

Prolog不擅长处理列表的尾部,但擅长处理列表的头部,因此我们欺骗并更改了lijstSom/2的定义,以声明列表是按相反的顺序给出的:

lijstSom[3,2,1],6

现在是一些代码

=是与运算符相等的常数。要使用它,我们需要发布use_modulelibraryclpfd。先指挥

lijstSom([],0).
lijstSom([K|Rest],N) :- lijstSom([Rest],T), T+K #= N.
以上内容遵循lijstSom的数学要求,并允许Prolog处理器执行其计算:在第二个子句中,它可以从大小为a-1的列表的值计算大小为a的列表的值,从总是减少列表长度的阶梯上下降,直到到达lijstSom[],0的终止情况

但是我们没有提到任何关于单调递减1的列表。 让我们更准确地说:

lijstSom([],0) :- !.
lijstSom([1],1) :- ! .
lijstSom([K,V|Rest],N) :- K #= V+1, T+K #= N, lijstSom([V|Rest],T).
更好

我们还添加了“!”告诉Prolog处理器不要寻找超过这一点的替代解决方案,因为我们对算法的了解比以往任何时候都要多。另外,第三行是有效的,但这仅仅是因为我在运行下面的测试并通过测试后得到了它

如果检查失败,Prolog处理器将显示false-输入没有解决方案。这正是我们想要的

但它有效吗?在这台杰出的物理机器的数学性方面,我们能走多远

负载库CLPFD用于约束和单元测试:

将其放入一个文件x.pl中,您可以使用[x]别名consult'x'加载该文件,或使用Prolog REPL上的make重新加载该文件:

:- use_module(library(clpfd)).

lijstSom([],0) :- 
   format("Hit case ([],0)\n"),!.
lijstSom([1],1) :-
   format("Hit case ([1],1)\n"),!.
lijstSom([K,V|Rest],N) :- 
   format("Called with K=~w, V=~w, Rest=~w, N=~w\n", [K,V,Rest,N]),
   K #= V+1, 
   T+K #= N,   
   T #> 0, V #> 0, % needed to avoid infinite descent
   lijstSom([V|Rest],T).

:- begin_tests(listsom).

test("0 verify") :- lijstSom([],0).
test("1 verify") :- lijstSom([1],1).
test("3 verify") :- lijstSom([2,1],3).
test("6 verify") :- lijstSom([3,2,1],6).

test("0 construct") :- lijstSom(L,0) , L = [].
test("1 construct") :- lijstSom(L,1) , L = [1].
test("3 construct") :- lijstSom(L,3) , L = [2,1].
test("6 construct") :- lijstSom(L,6) , L = [3,2,1]. 

test("0 sum") :- lijstSom([],S) , S = 0.
test("1 sum") :- lijstSom([1],S) , S = 1.
test("3 sum") :- lijstSom([2,1],S) , S = 3.
test("6 sum") :- lijstSom([3,2,1],S) , S = 6.

test("1 partial") :- lijstSom([X],1) , X = 1. 
test("3 partial") :- lijstSom([X,1],3) , X = 2. 
test("6 partial") :- lijstSom([X,2,1],6) , X = 3. 

test("1 extreme partial") :- lijstSom([X],S) , X = 1, S = 1.
test("3 extreme partial") :- lijstSom([X,1],S) , X = 2, S = 3.
test("6 extreme partial") :- lijstSom([X,2,1],S) , X = 3, S = 6.

test("6 partial list") :- lijstSom([X|L],6) , X = 3, L = [2,1]. 

% Important to test the NOPES

test("bad list", fail) :- lijstSom([3,1],_).
test("bad sum", fail) :- lijstSom([3,2,1],5).
test("reversed list", fail) :- lijstSom([1,2,3],6).
test("infinite descent from 2", fail) :- lijstSom(_,2).
test("infinite descent from 9", fail) :- lijstSom(_,9).

:- end_tests(listsom).
然后


你会怎么说?是的,他可能会抱怨一些事情。

请记住,Prolog不会返回任何东西。它要么成功,要么失败。你的意思不是sumlist吗?@Enigmativity你完全正确。这就是我想说的^^^@DavidTonhofer是的,我是说那个,忘了下划线。请不要忘了在问题旁边打勾以结束它。请记住,Prolog不会返回任何内容。它要么成功,要么失败。你的意思不是sumlist吗?@Enigmativity你完全正确。这就是我想说的^^^@DavidTonhofer是的,我是说那个,忘了下划线。请不要忘了在问题旁边打勾来结束它。嘿,大卫,哇,谢谢你这么快回答了这么多细节。在prolog中,我确实很难在列表的末尾工作,无法找到解决方法。在阅读了所有的代码并测试了一些之后,
例如,当询问时,它不会返回false李斯特索姆,9岁。很简单,因为它一直在搜索,所以必须有一些限制,使最后一个值不能低于0,因为如果我们知道这是不可能的,对吗?无论如何,感谢您的回复。这很有帮助:D@Flynce是的,说得好。看,我错过了那个案子。在这一点上,它变得有点冒险,因为我不完全确定CLPFD和它的约束操作符=应该等于什么,并且>应该大于它所能做的,这是远离一切的代价,放弃is的低级编程,或者使用if-then的显式案例管理。。。我想是吧。然而,一项测试表明,添加T>0,V>0确实有效&捕捉到无限下降。代码相应地更改。我还为一些输出添加了一个格式调用。非常感谢,我确实发现为了也能工作,现在我很好奇如何将这个返回值带到另一个函数中,以输出反转列表的反转列表,如图所示,可以反转列表。但我不确定如何将函数的输出放入该函数中。在Prolog中是否可以存储值?我想不起来曾经这样做过。无论如何。非常感谢,你帮了大忙@Flynce您可以使用assertz/2和retract/2将值存储在数据库中-这实际上类似于修改程序,很少使用。您应该做的是像烫手山芋一样将值从一个谓词传递到下一个谓词:pIn1、Out1、qOut1、Out2、rOut2、OutFinal。@Flynce、nvm我也已经计算出了剪切。再次感谢Hey David,Waow,感谢您如此快速地给出如此详细的回复。在prolog中,我确实很难在列表的末尾工作,无法找到解决方法。在阅读了所有代码并测试了一些代码之后,它在询问示例时不会返回false李斯特索姆,9岁。很简单,因为它一直在搜索,所以必须有一些限制,使最后一个值不能低于0,因为如果我们知道这是不可能的,对吗?无论如何,感谢您的回复。这很有帮助:D@Flynce是的,说得好。看,我错过了那个案子。在这一点上,它变得有点冒险,因为我不完全确定CLPFD和它的约束操作符=应该等于什么,并且>应该大于它所能做的,这是远离一切的代价,放弃is的低级编程,或者使用if-then的显式案例管理。。。我想是吧。然而,一项测试表明,添加T>0,V>0确实有效&捕捉到无限下降。代码相应地更改。我还为一些输出添加了一个格式调用。非常感谢,我确实发现为了也能工作,现在我很好奇如何将这个返回值带到另一个函数中,以输出反转列表的反转列表,如图所示,可以反转列表。但我不确定如何将函数的输出放入该函数中。在Prolog中是否可以存储值?我想不起来曾经这样做过。无论如何。非常感谢,你帮了大忙@Flynce您可以使用assertz/2和retract/2将值存储在数据库中-这实际上类似于修改程序,很少使用。您应该做的是像烫手山芋一样将值从一个谓词传递到下一个谓词:pIn1、Out1、qOut1、Out2、rOut2、OutFinal。@Flynce、nvm我也已经计算出了剪切。再次感谢