Prolog - 从两个列表中总结数字

时间:2013-04-10 18:02:23

标签: list lambda prolog add

我正在尝试编写prolog程序,该程序将两个列表中的项目相加并将结果显示在另一个列表中。

例如:

List1:

[1, 3, 4, 2]

List2:

[5, 1, 3, 0]

结果:

[6, 4, 7, 2]

到目前为止,我有这个:

list_sum([],[],[]).
list_sum([H1|T1],[H2|T2],L3):-list_sum(T1,T2,[X|L3]), X is H1+H2.

?-list_sum([1,2,3,4],[1,2,3,4],R),write(R).

6 个答案:

答案 0 :(得分:3)

如果您使用SWI-Prolog,您可以使用maplist,并在那里找到模块lambda:http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl

:- use_module(library(lambda)).

list_sum(L1, L2, L3) :-
    maplist(\X^Y^Z^(Z is X + Y), L1, L2, L3).

答案 1 :(得分:2)

@gusbro说的是什么。此外,您需要重新排列操作的顺序,并添加一些额外的特殊情况来处理不同长度的列表:

list_sum( []     , []     , []     ) .
list_sum( []     , [Y|Ys] , [Z|Zs] ) :- Z is 0+Y , list_sum( [] , Ys , Zs ) .
list_sum( [X|Xs] , []     , [Z|Zs] ) :- Z is X+0 , list_sum( Xs , [] , Zs ) .
list_sum( [X|Xs] , [Y|Ys] , [Z|Zs] ) :- Z is X+Y , list_sum( Xs , Ys , Zs ) .

您需要在上面的示例中移动评估(Z is X+Y),以便{<1}}在递归之前评估。这完成了两件事:

  • 首先,它使谓词尾递归,这意味着解决方案是迭代的,因此不会消耗堆栈空间。在您的代码中,直到整个递归完成后才会执行评估。每个中间总和都保留在堆栈中,并在您回来的路上从右到左进行评估。这意味着你将把你的筹码放在一个大的名单上。

  • 其次,在递归之前评估每个结果意味着快速失败。未与结果统一的第一个总和使整个操作失败。你的解决方案失败了。考虑10,000,000个项目列表,其中第一项不与结果列表中的第一项相加:您将遍历所有10,000,000个项目,然后 - 假设您没有打击堆栈 - 您开始从右到左评估总和。在最后一次评估之前,你的谓语不会失败。

答案 2 :(得分:1)

你快到了。 你的问题是总和的结果应该放在第二个子句的头部,而不是递归调用!

list_sum([H1|T1],[H2|T2],[X|L3]):-list_sum(T1,T2,L3), X is H1+H2.

请注意,您编写它的方式,作为结果“返回”的L3是一个列表,其中您已从隐性调用中删除了头部(X);而你的意思相反:将一个元素(X)添加到结果列表中。

答案 3 :(得分:1)

这是SWI-Prolog中的一个班轮:

list_sum(X,Y,S) :- maplist(plus, X,Y,S).

它也可以“落后”:

?- maplist(plus, [1,2,3],Y,[3,4,5]).
Y = [2, 2, 2].

答案 4 :(得分:0)

结果应该是一个列表,所以你不能只说X is H1+H2,因为X不是一个列表而你只是将列表的头部与一个变量匹配。由于同样的原因,list_sum([],[],0)也不正确。答案如下:

sum([],[],[]).
sum([H1| T1], [H2| T2], [ResH| ResT]) :- 
        sum(T1, T2, ResT),
        ResH is H1+H2.

但是当你运行自己的代码时,第一个X与H1 + H2匹配,在第二个递归调用X上有一个值,不能与T1 + T2的头匹配。所以输出no

答案 5 :(得分:0)

domains
list=integer*
predicates
add(list,list,list)
clauses
add([],[],[]).
add([V1X|X],[V1Y|Y],[V1Z|Z]):-add(X,Y,Z),V1Z=V1X+V1Y.