[英]Sum of even and odd numbers of a list in Prolog
我需要做的是编写一个带有数字列表的谓词,并返回一个由两个元素组成的列表,第一个是偶数的和,第二个是奇数之和。
例如:
?- sum([5,4,9,8,1,7], L).
L = [12, 22].
到目前为止我写了:
iseven(N) :-
0 is mod(N,2).
既然你已经定义了iseven/2
就可以使用它:
sum([],[0,0]).
sum([H|T],[N1,N2]):-
sum(T,[N3,N4]),
( iseven(H)
-> N1 is N3+H, N2 is N4
; N2 is N4+H, N1 is N3
).
例:
?-sum([5,4,9,8,1,7], L).
L = [12, 22].
使用不同子句的非if-then-else版本:
sum([],[0,0]).
sum([H|T],[N1,N2]):- sum(T,[N3,N2]), iseven(H), N1 is N3+H.
sum([H|T],[N1,N2]):- sum(T,[N1,N3]), \+ iseven(H), N2 is N3+H.
您也可以使用accumulators和if_ / 3编写此谓词。 此外,您可以将iseven/1
的单个目标合并到谓词中:
list_sums(L,S) :-
list_sums_(L,S,0-0).
list_sums_([],[E,O],E-O).
list_sums_([X|Xs],S,E0-O0) :-
M is X mod 2,
if_(M=0,(E1 is E0+X, O1 is O0),(E1 is E0, O1 is O0+X)),
list_sums_(Xs,S,E1-O1).
注意累加器是如何写成一对( EO
)的。 如果您可以自由选择两个总和的表示,则此对符号将是具有两个元素的列表的替代。 您的示例查询产生了所需的结果:
?- list_sums([5,4,9,8,1,7],L).
L = [12, 22].
而评论中的示例终止得更快:
?- length(L,100),maplist(=(1),L),time(list_sums(L,[A,B])).
% 703 inferences, 0.000 CPU in 0.000 seconds (100% CPU, 3426895 Lips)
L = [1, 1, 1, 1, 1, 1, 1, 1, 1|...],
A = 0,
B = 100.
但是,由于使用is/2
这只能在一个方向上工作。 如果您还想在另一个方向使用谓词,则可以选择使用CLP(FD)。 在那种情况下包括线
:- use_module(library(clpfd)).
在源文件中,用#=/2
替换list_sums_/3
所有出现的is/2
#=/2
:
list_sums_([],[E,O],E-O).
list_sums_([X|Xs],S,E0-O0) :-
M #= X mod 2,
if_(M=0,(E1 #= E0+X, O1 #= O0),(E1 #= E0, O1 #= O0+X)),
list_sums_(Xs,S,E1-O1).
您的示例查询仍会产生相同的结果,并且注释中的示例在可接受的时间内终止:
?- length(L,100),maplist(=(1),L),time(list_sums(L,[A,B])).
% 18,928 inferences, 0.004 CPU in 0.004 seconds (99% CPU, 4888152 Lips)
L = [1, 1, 1, 1, 1, 1, 1, 1, 1|...],
A = 0,
B = 100.
但这个谓词现在在两个方向都有效。 在某些情况下,Prolog可以毫不费力地找到具体的答案:
?- list_sums([A,B],[2,1]).
A = 2,
B = 1 ;
A = 1,
B = 2 ;
false.
在其他情况下,您可以获得剩余目标作为答案:
?- L=[A,B,C,D,E,F], list_sums(L,[12,22]).
L = [A, B, C, D, E, F],
A+B#=_G3306,
A mod 2#=0,
B mod 2#=0,
_G3306+C#=_G3342,
C mod 2#=0,
_G3342+D#=12,
D mod 2#=0,
E+F#=22,
E mod 2#=_G3402,
F mod 2#=_G3414,
_G3414 in 0..1,
dif(_G3414, 0),
_G3402 in 0..1,
dif(_G3402, 0) ;
...
在这些情况下,您可以将列表的元素限制为某个间隔,并使用label/1
来获取具体数字作为解决方案。 例如,您可以要求提供从0到7的六个数字的解决方案,Prolog将为您提供所有300个解决方案:
?- length(L,6), L ins 0..7, list_sums(L,[12,22]), label(L).
L = [6, 6, 1, 7, 7, 7] ;
L = [6, 6, 3, 5, 7, 7] ;
...
您可以使用函数方式:
one_sum(X, [SE,SO], [SE1, SO1]) :-
( X mod 2 =:= 0 ->
SE1 is SE+X, SO1 = SO
; SE1 = SE, SO1 is SO+X).
sum(L, S) :-
foldl(one_sum, L, [0,0], S).
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.