在 Prolog 中创建一个谓词,仅对列表中偶数的平方求和
Creating a predicate in Prolog that sums the squares of only the even numbers in a list
我正在尝试弄清楚如何在 prolog 中创建一个谓词,该谓词仅对给定列表中的偶数的平方求和。
预期输出:
?- sumsq_even([1,3,5,2,-4,6,8,-7], Sum).
Sum = 120 ;
false.
我知道该怎么做是从列表中删除所有奇数:
sumsq_even([], []).
sumsq_even([Head | Tail], Sum) :-
not(0 is Head mod 2),
!,
sumsq_even(Tail, Sum).
sumsq_even([Head | Tail], [Head | Sum]) :-
sumsq_even(Tail, Sum).
这给了我:
Sum = [2, -4, 6, 8]
而且我还知道如何对列表中所有数字的平方求和:
sumsq_even([], 0)
sumsq_even([Head | Tail], Sum) :-
sumsq_even(Tail, Tail_Sum),
Sum is Head * Head + Tail_Sum.
但我似乎无法弄清楚如何将这两者联系在一起。我在想我可能走错了路,但我不确定如何定义适当的关系才能让它有意义。
谢谢!
将您的问题分解成更小的部分。正如您已经说过的,您有两个不同的功能应该结合起来:
- 从列表中删除奇数 (
even
)
- 对列表中所有数字的平方求和 (
sumsq
)
因此,首先,为不同的功能使用不同的谓词名称:
even([], []).
even([Head | Tail], Sum) :-
not(0 is Head mod 2),
!,
even(Tail, Sum).
even([Head | Tail], [Head | Sum]) :-
even(Tail, Sum).
sumsq([], 0).
sumsq([Head | Tail], Sum) :-
sumsq(Tail, Tail_Sum),
Sum is Head * Head + Tail_Sum.
在第三个谓词中,您现在可以组合两个后续的较小步骤:
sumsq_even(List, Sum) :-
even(List, Even_List),
sumsq(Even_List, Sum).
在此规则中,首先将(输入)列表减少为偶数元素 (Even_List
),然后计算平方和。
这是您的示例的结果:
sumsq_even([1,3,5,2,-4,6,8,-7], Sum).
S = 120.
您实际上可以同时完成这两项任务(过滤偶数并将它们相加):
:- use_module(library(clpfd)).
nums_evensumsq([],0).
nums_evensumsq([X|Xs],S0) :-
X mod 2 #= 0,
nums_evensumsq(Xs,S1),
S0 #= S1 + X * X.
nums_evensumsq([X|Xs],S) :-
X mod 2 #= 1,
nums_evensumsq(Xs,S).
查询谓词给出了想要的结果:
?- nums_evensumsq([1,3,5,2,-4,6,8,-7],S).
S = 120 ? ;
no
您可以使用 if_/3 定义的 here:
来写得更短
nums_evensumsq([],0).
nums_evensumsq([X|Xs],S0) :-
nums_evensumsq(Xs,S1),
Y #= X mod 2,
if_(Y = 0, S0 #= S1 + X * X, S0 #= S1).
请注意,if_/3 的第一个参数中的比较是根据 here 定义的 =/3 完成的。
掌握了基础知识后,您可能会对了解内置函数感兴趣。库 aggregate,提供了一种处理列表的简单方法,使用 member/2 作为列表元素 'accessor':
sumsq_even(Ints, Sum) :-
aggregate(sum(C), I^(member(I, Ints), (I mod 2 =:= 0 -> C is I*I ; C = 0)), Sum).
:- use_module(library(clpfd)).
:- use_module(library(lambda)).
zs_sumevensq(Zs, S) :-
maplist(\Z^X^(X #= Z*Z*(1-(Z mod 2))), Zs, Es),
sum(Es, #=, S).
OP 给出的示例查询:
?- zs_sumevensq([1,3,5,2,-4,6,8,-7], S).
S = 120.
我正在尝试弄清楚如何在 prolog 中创建一个谓词,该谓词仅对给定列表中的偶数的平方求和。
预期输出:
?- sumsq_even([1,3,5,2,-4,6,8,-7], Sum).
Sum = 120 ;
false.
我知道该怎么做是从列表中删除所有奇数:
sumsq_even([], []).
sumsq_even([Head | Tail], Sum) :-
not(0 is Head mod 2),
!,
sumsq_even(Tail, Sum).
sumsq_even([Head | Tail], [Head | Sum]) :-
sumsq_even(Tail, Sum).
这给了我:
Sum = [2, -4, 6, 8]
而且我还知道如何对列表中所有数字的平方求和:
sumsq_even([], 0)
sumsq_even([Head | Tail], Sum) :-
sumsq_even(Tail, Tail_Sum),
Sum is Head * Head + Tail_Sum.
但我似乎无法弄清楚如何将这两者联系在一起。我在想我可能走错了路,但我不确定如何定义适当的关系才能让它有意义。
谢谢!
将您的问题分解成更小的部分。正如您已经说过的,您有两个不同的功能应该结合起来:
- 从列表中删除奇数 (
even
) - 对列表中所有数字的平方求和 (
sumsq
)
因此,首先,为不同的功能使用不同的谓词名称:
even([], []).
even([Head | Tail], Sum) :-
not(0 is Head mod 2),
!,
even(Tail, Sum).
even([Head | Tail], [Head | Sum]) :-
even(Tail, Sum).
sumsq([], 0).
sumsq([Head | Tail], Sum) :-
sumsq(Tail, Tail_Sum),
Sum is Head * Head + Tail_Sum.
在第三个谓词中,您现在可以组合两个后续的较小步骤:
sumsq_even(List, Sum) :-
even(List, Even_List),
sumsq(Even_List, Sum).
在此规则中,首先将(输入)列表减少为偶数元素 (Even_List
),然后计算平方和。
这是您的示例的结果:
sumsq_even([1,3,5,2,-4,6,8,-7], Sum).
S = 120.
您实际上可以同时完成这两项任务(过滤偶数并将它们相加):
:- use_module(library(clpfd)).
nums_evensumsq([],0).
nums_evensumsq([X|Xs],S0) :-
X mod 2 #= 0,
nums_evensumsq(Xs,S1),
S0 #= S1 + X * X.
nums_evensumsq([X|Xs],S) :-
X mod 2 #= 1,
nums_evensumsq(Xs,S).
查询谓词给出了想要的结果:
?- nums_evensumsq([1,3,5,2,-4,6,8,-7],S).
S = 120 ? ;
no
您可以使用 if_/3 定义的 here:
来写得更短nums_evensumsq([],0).
nums_evensumsq([X|Xs],S0) :-
nums_evensumsq(Xs,S1),
Y #= X mod 2,
if_(Y = 0, S0 #= S1 + X * X, S0 #= S1).
请注意,if_/3 的第一个参数中的比较是根据 here 定义的 =/3 完成的。
掌握了基础知识后,您可能会对了解内置函数感兴趣。库 aggregate,提供了一种处理列表的简单方法,使用 member/2 作为列表元素 'accessor':
sumsq_even(Ints, Sum) :-
aggregate(sum(C), I^(member(I, Ints), (I mod 2 =:= 0 -> C is I*I ; C = 0)), Sum).
:- use_module(library(clpfd)). :- use_module(library(lambda)). zs_sumevensq(Zs, S) :- maplist(\Z^X^(X #= Z*Z*(1-(Z mod 2))), Zs, Es), sum(Es, #=, S).
OP 给出的示例查询:
?- zs_sumevensq([1,3,5,2,-4,6,8,-7], S).
S = 120.