【问题标题】:Prolog - summing numbers from two listsProlog - 对两个列表中的数字求和
【发布时间】:2013-04-10 18:02:22
【问题描述】:

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

例如:

列表1:

[1, 3, 4, 2]

列表2:

[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).

【问题讨论】:

    标签: list lambda prolog add


    【解决方案1】:

    如果您使用 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).
    

    【讨论】:

    • YAP 内置
    【解决方案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),以便在递归之前评估 Z。这完成了两件事:

    • 首先,它使谓词tail-recursive,这意味着解决方案是迭代的,因此不会占用堆栈空间。在您的代码中,直到整个递归完成后才会执行评估。每个中间和都保存在堆栈中,并在您返回时从右到左进行评估。这意味着你会在一个大名单上炸掉你的筹码。

    • 其次,在递归之前评估每个结果意味着您快速失败。与结果不统一的第一个总和使整个操作失败。您的解决方案失败缓慢。考虑 10,000,000 个项目列表,其中第一个项目的总和不等于结果列表中的第一个项目:您将遍历所有 10,000,000 个项目,然后——假设你没有破坏你的堆栈——你开始从右到左计算总和。在最后一次评估之前,您的谓词不会失败​​。

    【讨论】:

    • “直到最后一次评估”......这可能/应该是非常第一个。 :) 很好的答案!
    【解决方案3】:

    它是 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】:

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

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

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

      【讨论】:

      • @NicholasCarey:同意你的最后一个条款,我只是想展示 OP 的问题并在不改变他想要解决问题的方式的情况下进行修复。我不同意你的第二个和第三个条款,当列表长度不同时,程序会成功。
      • 比较看需求,n'est-ce pas?
      • @NicholasCarey:oui,但我并没有从他的问题中推断出那些 OPs 的要求。
      【解决方案5】:

      结果应该是一个列表,所以你不能只说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

      【讨论】:

        【解决方案6】:
        domains
        list=integer*
        predicates
        add(list,list,list)
        clauses
        add([],[],[]).
        add([V1X|X],[V1Y|Y],[V1Z|Z]):-add(X,Y,Z),V1Z=V1X+V1Y.
        

        【讨论】:

          猜你喜欢
          • 2014-07-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-03-22
          • 2016-01-12
          • 2013-02-07
          相关资源
          最近更新 更多