List 在Prolog中,有没有一种方法可以只对包含字母和整数的对列表中的整数求和?

List 在Prolog中,有没有一种方法可以只对包含字母和整数的对列表中的整数求和?,list,prolog,List,Prolog,我很难找出如何找到成对列表中的整数之和,如下所示: [[a, 1], [b, 2], [c, 3], [d, 4]] 我尝试过这样的方法,因为它让人联想到正则和函数: sum([], 0). sum([[_,Head]|[_,Tail]], Sum) :- sum([_,Tail], Sum2), Sum is Head+Sum2. 电话是: sum([[a, 1], [b, 2], [c, 3], [d, 4]], Total), write('Sum = '), writ

我很难找出如何找到成对列表中的整数之和,如下所示:

[[a, 1], [b, 2], [c, 3], [d, 4]]
我尝试过这样的方法,因为它让人联想到正则和函数:

sum([], 0).
sum([[_,Head]|[_,Tail]], Sum) :-
    sum([_,Tail], Sum2),
    Sum is Head+Sum2.
电话是:

sum([[a, 1], [b, 2], [c, 3], [d, 4]], Total),
write('Sum = '), write(Total).

但这不起作用。它打印出false,此时它应该打印出总和,这里是10。

我认为将其分为两个任务可能会有所帮助:

  • 创建每个子列表第二项的新列表;及
  • 总结一下这个清单
  • 这使得解决这两个问题变得更容易,而且您现在有两个额外的谓词可用于其他目的

    我们可以通过以下方式获得子列表第二项的列表:

    item2list([], []).
    item2list([[_, X|_]|T], [X|T2]) :-
        item2list(T, T2).
    
    或者我们可以使用和:

    或者我们可以根据和编写
    item2list

    尽管这里的谓词不是双向的

    例如:

    ?- item2list([[a, 1], [b, 2], [c, 3], [d, 4]], L).
    L = [1, 2, 3, 4].
    

    我把总结列表作为一个练习。

    在您试图定义谓词
    sum/2
    时,您没有正确处理列表列表。尝试:

    sum(Lists, Sum) :-
        sum(Lists, 0, Sum).
    
    sum([], Sum, Sum).
    sum([[_,N]| Lists], Sum0, Sum) :-
        Sum1 is Sum0 + N,
        sum(Lists, Sum1, Sum).
    
    此版本使用累加器启用尾部递归定义。电话示例:

    | ?- sum([[a, 1], [b, 2], [c, 3], [d, 4]], Sum).
    
    Sum = 10
    yes
    

    每当你期望成功的目标失败时,将此视为学习的机会(logic earn=earn logic的缩写)。毕竟,这就是Prolog,它的意思是用逻辑进行编程。那么,程序中的逻辑在哪里呢

    目前你的程序失败了,但你希望它会成功。罪犯在哪里?让我们对您的程序进行概括,使生成的程序仍然失败,但要小得多。概括程序有两种简单的方法:

    • 删除目标(通过添加前缀
      *

    • 删除术语(将
      术语
      替换为
      术语*/

    我们可以盲目地这样做。无需了解您的计划。只需重新检查目标是否仍然失败。以下是我第一次尝试时得出的结论:

    :- op(950, fy, *). * _G_0. % ignore the argument _G_0 sum([], _/*0*/). sum([_/*[_,Head]*/|[_,Tail]], Sum) :- * sum([_,Tail], Sum2), * Sum is Head+Sum2. ?- sum([_/*[a, 1]*/, _/*[b, 2]*/, _/*[c, 3]*/, _/*[d, 4]*/], Total). false. % gnah - still fails 因此,只有两种长度的列表是可能的:空列表和一个包含三个元素的列表。请注意,我们目前有一个谓词的通用版本。因此,不能保证我们会找到两种长度的解决方案。但是,我们可以100%确定,对于所有其他长度,都不会有解决方案

    让我们回到原始程序,询问最一般的问题:

    ?- sum(Os, Total).
       Os = [], Total = 0
    ;  false.
    
    ,只有一个解。甚至没有一个求和([| | |,Total)的解

    因此,让我们再次概括该计划,但现在关于这个失败的目标:

    sum([], _/*0*/). sum([_/*[_,Head]*/|[_,Tail|_/*[]*/]], Sum) :- sum([_,Tail], Sum2), * Sum is Head+Sum2. ?- Os = [_|_], sum(Os, Total). false. 总和([],/*0*/)。 求和([/*[[uu,Head]*/[uu,Tail].[u/*[]*/]],求和):- 总和([[uu,Tail],Sum2), *总和为总合+总合2。 ?-Os=[124; 124;],总和(Os,总计)。 错。 在这一部分中,肯定还有一个错误。事实上,目标
    sum([\uu,Tail],Sum2)
    是罪魁祸首:它是一个正好包含两个元素的列表,但规则至少需要三个元素

    有关实际修复,请参阅其他答案


    此方法适用于像您这样的纯单调程序。

    sum([[[uu,Head].[[uu,Tail]],sum)
    ->这表示它只匹配一个包含两个项目的列表,而不匹配其他项目。整个尾部部分需要一个名称。这个问题是昨天提出的,这里有一个答案:如果答案是你想要的。回答者是对的:这是一个很好的学习机会。但简单的答案是:你说了[\uu,tail]当您指的是Tail时。列表的其余部分不是两个要称为u和Tail的项,而是三个项,最好统称为Tail。
    findall/3
    +
    member/2
    将为您的
    item2list/2
    谓词提供一个显著更快的实现,但是
    findall/3
    会干扰约束。
    maplist/3
    solu这个问题不存在。
    | ?- sum(Xs, Sum).
       Xs = []
    ;  Xs = [_A,_B,_C].
    
    ?- sum(Os, Total).
       Os = [], Total = 0
    ;  false.
    
    sum([], _/*0*/). sum([_/*[_,Head]*/|[_,Tail|_/*[]*/]], Sum) :- sum([_,Tail], Sum2), * Sum is Head+Sum2. ?- Os = [_|_], sum(Os, Total). false.