I'm having trouble figuring out how to find the sum of the integers that are in a list of pairs like so:
[[a, 1], [b, 2], [c, 3], [d, 4]]
I tried something like this, since it is reminiscent of a regular sum function:
sum([], 0).
sum([[_,Head]|[_,Tail]], Sum) :-
sum([_,Tail], Sum2),
Sum is Head+Sum2.
With the call being:
sum([[a, 1], [b, 2], [c, 3], [d, 4]], Total),
write('Sum = '), write(Total).
But that doesn't work. It prints out false, when it should print out the sum, which would be 10 here.
I think it might help to split this into two tasks:
This makes it easier to tackle the two problems, and furthermore you now have two extra predicates that can be used for other purposes.
We can obtain a list of the second item of the sublists with:
or we can use
maplist/3
[swi-doc] andnth1/3
[swi-doc]:or we can write
item2list
in terms offindall/3
[swi-doc] andmember/2
[swi-doc]:although here the predicate is not bidirectional.
For example:
I leave summing up that list as an exercise.
In your attempt to define the predicate
sum/2
, you're not handling the lists of lists correctly. Try:This version uses an accumulator to enable a tail-recursive definition. Sample call:
Whenever a goal fails that you expect to succeed, see this as an opportunity to learn (short form for logic earn = earn logic). After all, this is Prolog which was meant to mean Programming in Logic. So where is the logic in your program?
For the moment your program fails, but you expected it to succeed. Where is the culprit? Let's generalize your program such that the resulting program still fails, but is much smaller. There are two easy ways to generalize a program:
remove goals (by adding a prefix
*
)remove terms (replacing
term
by_
/*term*/We can do this pretty blindly. No need to understand your program. Just recheck that the goal still fails. Here is what I came up with on my first try:
One problem has to be in the remaining visible part. Too difficult to figure out? Let Prolog explain it to you by querying the most general query:
So only two lengths of lists are possible: The empty list and a list with three elements. Note that we have currently a generalized version of the predicate. So there is no guarantee that we will find solutions for both lengths. However, we can be 100% sure that for all other lengths there will be no solution.
Let's get back at the original program and ask the most general query:
Oh no, there is a single solution only. And not even a single solution for
sum([_|_], Total)
.So let's generalize the program again but now with respect to this failing goal:
In this part there must be a further error. And in fact, the goal
sum([_,Tail], Sum2)
is the culprit: It is about a list of exactly two elements, but the rule wants at least threeFor the actual fixes, see the other answers.
This method works for pure, monotonic programs such as yours.