Search code examples
prologclpfd

Creating a predicate in Prolog that sums the squares of only the even numbers in a list


I'm trying to figure out how to create a predicate in prolog that sums the squares of only the even numbers in a given list.

Expected output:

?- sumsq_even([1,3,5,2,-4,6,8,-7], Sum).

Sum = 120 ;

false.

What I know how to do is to remove all the odd numbers from a list:

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).

Which gives me:

Sum = [2, -4, 6, 8]

And I also know how to sum all the squares of the numbers in a list:

sumsq_even([], 0)
sumsq_even([Head | Tail], Sum) :-
    sumsq_even(Tail, Tail_Sum),
    Sum is Head * Head + Tail_Sum.

But I can't seem to figure out how to connect these two together. I'm thinking I may have gone the wrong way about it but I'm not sure how to define proper relationships to get it to make sense.

Thanks!


Solution

  • Split your problem into smaller parts. As you already said, you have two different functionalities that should be combined:

    • remove odd numbers from a list (even)
    • sum all the squares of the numbers in a list (sumsq)

    So, in the first place, use different predicate names for different functionalities:

    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.
    

    In a third predicate you can now combine the two subsequent smaller steps:

    sumsq_even(List, Sum) :-
        even(List, Even_List),
        sumsq(Even_List, Sum).
    

    In this rule, first the (input) list is reduced to even elements (Even_List) and after that the sum of the squares are calculated.

    This is the result for your example:

    sumsq_even([1,3,5,2,-4,6,8,-7], Sum).
    S = 120.