Пролог - сумма членов списка

Я пытался найти окружность страны в Прологе.

У меня есть готовый предикат

borders(Country1, Country2, Length)

а также

setof(Item, Condition, Set) 

который дает список всех элементов в наборе, которые удовлетворяют условию.

Чтобы получить окружность, я попытался сделать это:

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.

... но результат, который я получаю, это только длина между двумя странами в предикате границы.

Мой тест:

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

правила:

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

Почему не C стать суммой этих чисел?

2 ответа

Я поменял окружность /2 аргумента, но вы поняли...

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

Проблема связана с привязкой переменной для другой страны. Сначала это выглядит сумасшедшим:

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

Но если вы назовете эту переменную, станет ясно, что происходит:

?- 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].

Он не может сгруппировать их, потому что другая страна отличается, даже если вас не интересует значение, которое получила привязка. Правильное решение с setof/3 это сделать OtherCountry экзистенциально количественно, что не имеет значения для целей группировки:

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

В setof/3 а также bagof/3экзистенциальная количественная оценка - это способ сказать, что OtherCountry будет принимать различные значения, но вы не заинтересованы в них для целей группировки. Есть много сценариев, где findall/3 будет давать только один результат, но вам могут потребоваться отдельные группировки на основе некоторых других переменных в параметре Goal, поэтому я думаю, что полезно знать об этой технике, даже если findall/3 это, вероятно, более простое решение в этом случае. Дополнительную дискуссию можно найти по этому ответу.

Другие вопросы по тегам