我正在尝试编写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).
答案 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.