简体   繁体   中英

Prolog - sum of list members

I have been trying to find the circumference of a country in Prolog.

I have the finished predicate

borders(Country1, Country2, Length)

and

setof(Item, Condition, Set) 

which gives a list of all items into the set which fulfill the condition.

To get the circumference I tried doing this:

circumference(C, Country) :-
    setof(X, borders(Country,_,X), Set),
    sum_list(Set,C).

sum_list([], 0).
sum_list([H|T], C) :-
   sum_list(T, Rest),
   C is H + Rest.

... but the output I'm getting is only the length between two countries in the border predicate.

My test:

?– circumference(C,angola).
C = 201 ;
C = 1376 ;
C = 2511 ;
C = 1110.

rules:

borders(angola,namibia,1376).
borders(angola,congo,201).
borders(angola,zambia,1110).
borders(angola,zaire,2511).

Why doesn't C become the sum of these numbers?

我交换了周长/ 2个参数,但你明白了......

circumference(Country,C) :- aggregate(sum(Y),S^borders(Country,S,Y),C).

The problem has to do with the variable binding for the other country. At first it looks crazy:

?- setof(X, borders(Country,_,X), Set).
Country = angola,
Set = [201] ;
Country = angola,
Set = [1376] ;
Country = angola,
Set = [2511] ;
Country = angola,
Set = [1110].

But if you name that variable it becomes clear what's going on:

?- setof(X, borders(Country,OtherCountry,X), Set).
Country = angola,
OtherCountry = congo,
Set = [201] ;
Country = angola,
OtherCountry = namibia,
Set = [1376] ;
Country = angola,
OtherCountry = zaire,
Set = [2511] ;
Country = angola,
OtherCountry = zambia,
Set = [1110].

It can't group them together because the other country differs, even if you're not interested in the value that binding received. The right solution with setof/3 is to make OtherCountry existentially quantified, which makes it not matter for the purposes of the grouping:

?- setof(X, OtherCountry^borders(Country,OtherCountry,X), Set).
Country = angola,
Set = [201, 1110, 1376, 2511].

In setof/3 and bagof/3 , existential quantification is a way of saying that OtherCountry will take on various values but you're not interested in them for the purposes of the grouping. There are lots of scenarios where findall/3 will only produce a single result but you may want separate groupings based on some of the other variables in the Goal parameter, so I think it's good to know about this technique even though findall/3 is probably a more straightforward solution in this case. More discussion can be found on this answer .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM