使用Prolog汇总列表

时间:2015-12-25 09:57:38

标签: list prolog clpfd

我想将所有列表元素的总和大于某个给定的数字。以下是描述:

  

sumup(L, N, GREATN, GEN)将列表L的成员(大约GREATN)加到变量N中,并将这些成员放入列表GEN。< / p>      

示例查询:

?- sumup([8, 6, 10, 3, 9, 12], N, 7, GEN).
GEN = [8, 10, 9, 12],                             % expected answer
N = 39.                                           % 8+10+9+12 = 39

以下是我的代码:

sum_list([], 0).
sum_list([H|T], Sum) :- 
    H > 3,
    sum_list(T, Rest),
    Sum is H + Rest.
sum_list([H|T], Sum) :-
    H < 3,
    write('').

我尝试了递归方式,但我失败了。我该如何解决?

3 个答案:

答案 0 :(得分:2)

看看你的问题和你的代码,我注意到了一些事情:

  • 虽然您多次谈到“数字”,但您的样本仅为整数。我们可以忽略非整数(浮点数,有理数)并只处理整数吗?我想是的。
  • 有一个自动加载的SWI-Prolog library(lists)谓词sum_list/2 调用谓词sum_list/2是一个不幸的选择。 让我们选择另一个名字!
  • 您对sum_list/2的定义包含三个条款:

    1. sum_list([], 0). 好吧!
    2. sum_list([H|T], Sum) :- H > 3, sum_list(T, Rest), Sum is H + Rest.

      注意H > 3?为什么硬编码常数整数3

    3. sum_list([H|T], Sum) :- H < 3, write('').

      • 该子句不是递归的。我们需要查看所有列表元素来计算总和,而不是停留在满足H的第一个列表元素H < 3

      • write('')有什么用?我没有看到任何。

      • 目标H < 3有什么用?如上所述,为什么要对整数3进行硬编码?

      • 第2条涵盖H > 3。第3条涵盖H < 3 H = 3怎么样?

在此回答中,我们使用了中的

以下是基于sumup/4的直接定义。虽然可以通过多种方式进行改进(更好的确定性,累加器式,可能还有一些聪明的冗余约束也可能有所帮助),但暂时它是一个不错的第一枪:

:- use_module(library(clpfd)).

sumup([], 0, _, []).
sumup([Z|Zs], S0, P, [Z|Xs]) :-
   Z  #> P,
   S0 #= S+Z,
   sumup(Zs, S, P, Xs).
sumup([Z|Zs], S, P, Xs) :-
   Z #=< P,
   sumup(Zs, S, P, Xs).

OP给出的示例查询:

?- sumup([8,6,10,3,9,12], N, 7, GEN).
   N = 39, GEN = [8,10,9,12]             % expected answer
;  false.                                % leftover useless choicepoint

答案 1 :(得分:2)

无需编写递归代码!只需使用tfilter/3(#<)/3clpfd:sum/3,就像这样:

:- use_module(library(clpfd)).

sumup(Zs, S, P, Xs) :-
   tfilter(#<(P), Zs, Xs),
   sum(Xs, #=, S).

示例查询:

?- sumup([8,6,10,3,9,12], S, 7, Xs).
S = 39, Xs = [8,10,9,12].                       % expected result

请注意,上述查询确定性地成功 - 明显优于this previous answer

加分!由于sumup/4的实施是单调,我们知道上述查询的解决方案也是查询的每个泛化的解决方案集。找你自己!

?- sumup([8,6,10,3,9,12], S, E, Xs).
   S = 48, E in inf..2  , Xs = [8,6,10,3,9,12]
;  S = 45, E in   3..5  , Xs = [8,6,10,  9,12]
;  S = 39, E in   6..7  , Xs = [8,  10,  9,12]  % <==== solution of above query
;  S = 31, E in   8..8  , Xs =     [10,  9,12]
;  S = 22, E in   9..9  , Xs =     [10,    12]
;  S = 12, E in  10..11 , Xs =            [12]
;  S =  0, E in  12..sup, Xs =              []
;  false.

答案 2 :(得分:1)

在SWI-Prolog中,您可以使用fold并简单查询:

L=[8, 6, 10, 3, 9, 12], include(<(7),L,Gen), foldl(plus,Gen,0,N).

以便将sumup写为

sumup(L,N,GreatN,Gen) :-
    include(<(GreatN),L,Gen),
    foldl(plus,Gen,0,N).

plus/3是一个算术谓词,在我们的案例中效果很好。