Prolog:把一个数字分解成一系列递增的整数



在大学里做了一些Prolog并做了一些练习后,我决定更进一步,尽管我承认我对递归理解不太好,但我明白了这个概念和想法,但如何编码它仍然是我的一个问题。这就是为什么我很好奇是否有人知道如何帮助解决这个问题。

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

因此,对于45,[1,2,3,4,5,6,7,8,9]是正确的。

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

因此,给定谓词lijstSom(L,S)(荷兰语为listSum),给定

?- lijstSom(L, 45)
L = [1,2,3,4,5,6,7,8,9];
False

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

但为此,你需要计数器,我发现在递归中很难理解这一点。

编辑:

递归中的步骤。

基本情况空列表,0(计数器nr,即减去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

但可以将谓词lijstSom(List, Sum)看作是将某些整数列表与其和相关联,而不是计算整数列表的和。为什么是"特定列表"?因为我们有一个约束,即整数列表中的整数必须以1为增量单调递增,从1开始。

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

"谈谈lijstSom/2的第一个自变量和lijstSom/2的第二个自变量之间的关系(假设第一个是单调递增的整数列表,第二个是整数):

lijstSom([1,2,3], Sum)

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

lijstSom(L, 6)

应该返回true(因为是的,至少有一个解决方案),并且给出解决方案[1,2,3]

lijstSom([1,2,3], 6)

返回true(因为是的,[1,2,3]有一个和6);不需要进一步的信息。

lijstSom(L, S)

应该是的无穷级数和解对("生成解")。

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

lijstSom([1,2,3], 7)

返回false("fail"),因为7不在lijstSom[1,2,3]的关系中,因为7=/=1+2+3。

人们甚至可能希望Prolog处理器能说出一些有趣的东西:

lijstSom([1,2,X], 6)

X = 3

甚至

lijstSom([1,2,X], S)

X = 3
S = 6

事实上,lijstSom/2在数学上和物理上一样神奇,也就是说:

  • 可以不受限制地访问列表的完整表<->和关系漂浮在柏拉图数学空间的某个地方
  • 能够在不到无穷多的步骤中找到正确的条目
  • 并输出

当然,由于非常实际的原因,我们被限制在低指数和有限数量的D可分辨符号的多项式算法中。糟透了!

因此,首先使用归纳定义定义lijstSom(L,S)

  • lijstSom([a list with final value N],S)。。。如果。。。lijstSom([a list],S-N
  • lijstSom([],0),因为空列表的总和为0

这很好,因为它提供了一个食谱,可以将任意长度的列表最终缩减为0大小的列表,同时保持其总和!

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

lijstSom([3,2,1], 6)

现在是一些代码。

#=是库(clpfd)中的"常数等于"运算符。要使用它,我们需要首先发出use_module(library(clpfd)).命令。

lijstSom([],0).
lijstSom([K|Rest],N) :- lijstSom([Rest],T), T+K #= N.

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

但我们还没有说任何关于单调递减的列表。更准确地说:

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

更好!

(我们还添加了"!",告诉Prolog处理器不要寻找超过这一点的替代解决方案,因为我们对算法的了解比以往任何时候都要多。此外,第三行可以工作,但这只是因为我在运行下面的测试并使其通过后就得到了它。)

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

但它有效吗?我们能在这个杰出的物理机器的"数学性"上走多远?

为约束加载library(clpfd),为单元测试使用library(plunit)

将其放入文件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=~wn", [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).

然后

?- run_tests(listsom).
% PL-Unit: listsom ...................... done
% All 22 tests passed

Dijkstra会怎么说?是的,他可能会抱怨什么。

最新更新