我想将所有列表元素的总和大于某个给定的数字。以下是描述:
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('').
我尝试了递归方式,但我失败了。我该如何解决?
答案 0 :(得分:2)
看看你的问题和你的代码,我注意到了一些事情:
library(lists)
谓词sum_list/2
调用谓词sum_list/2
是一个不幸的选择。
让我们选择另一个名字!您对sum_list/2
的定义包含三个条款:
sum_list([], 0).
好吧! sum_list([H|T], Sum) :- H > 3, sum_list(T, Rest), Sum is H + Rest.
注意H > 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
怎么样?
在此回答中,我们使用了clpfd中的swi-prolog。
以下是基于clpfd的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
,(#<)/3
和clpfd: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)