Lucky
Lucky

Reputation: 11

sum of setof in prolog

I have this predicate to get the sum of the length of all borders of a country. I could solve it with findall but I have to use setof. My facts look like this:

borders(sweden,finland,586).
borders(norway,sweden,1619).

My code

circumference(C, Country) :-
    findall(X, ( borders(Country, _, X) ; borders(_, Country, X)), Kms),
    sum_list(Kms, C). 

Upvotes: 1

Views: 183

Answers (2)

Lucky
Lucky

Reputation: 11

I ended up using this:

circumference(Z, Country) :- setof(X, Q^(borders(Q,Country,X);borders(Country,Q,X)),Border),
                    sum_list(Border,Z).


% Adds the numbers in a list. 
sum_list([], 0).
sum_list([H|T], Sum) :-
   sum_list(T, Rest),
   Sum is H + Rest.

Upvotes: 0

TA_intern
TA_intern

Reputation: 2422

You cannot find the sum using bagof directly, all you can do is make a list and then sum that list (but you knew that already). In SWI-Prolog there is library(aggregate) that does the bagging and the summing for you. With the facts you have, you would write:

?- aggregate(sum(X), Y^( borders(Y, sweden, X) ; borders(sweden, Y, X) ), Circumference).
Circumference = 2205.

If you instead must obey the whims of your instructor and type "bagof" yourself, or if you are not allowed to use a modern, open source, comprehensive Prolog implementation, you can use the same approach with bagof and manually build the list before summing it:

?- bagof(X, Y^( borders(Y, sweden, X) ; borders(sweden, Y, X) ), Borders).
Borders = [1619, 586].

For reasons that are lost in the mists of time the funny thing with the Var^Goal that you see in both aggregate and bagof is called "existentially qualifying the variables in Goal". You might also read that "^ prevents binding Var in Goal". I cannot explain what this really means.

Upvotes: 1

Related Questions