Пролог - сумма членов списка
Я пытался найти окружность страны в Прологе.
У меня есть готовый предикат
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
это, вероятно, более простое решение в этом случае. Дополнительную дискуссию можно найти по этому ответу.