#prolog
#пролог
Вопрос:
Это проблема suma( [ [ 1, 2, 3, 4 ], [ 2, 3, 4, 5 ], [ 3, 4, 5, 6 ] ], X), и мне нужно получить этот результат X = [10, 14, 18]. Я понятия не имею, как это выяснить. Пожалуйста, помогите
Ответ №1:
maplist/3
и foldl/4
и все обозначения (последние, доступные в SWI-Prolog) — ваши друзья.
suma(ListOfLists,ListOfSums) :-
maplist(
([Sublist,Sum]>>
(foldl(
[AccumIn,X,AccOut]>>(AccOut is AccumIn X),
Sublist,
0,
Sum))),
ListOfLists,
ListOfSums).
Таким образом:
?- suma( [ [ 1, 2, 3, 4 ], [ 2, 3, 4, 5 ], [ 3, 4, 5, 6 ] ], X ).
X = [10, 14, 18].
Это менее логическое программирование, чем функциональное программирование, но если у кого-то есть швейцарский армейский нож, его можно использовать!
maplist/3
: Вызывает цель, которая находится в позиции аргумента 0 для каждой пары[Sublist,Sum]
, гдеSublist
является элементом списка в позиции аргумента 1 (т.Е.ListOfLists
) иSum
является элементом списка в позиции аргумента 2 (т.Е.ListOfSums
), Причем оба элемента находятся в одной и той же позиции в своих соответствующих списках.- Вызываемая цель принимает
[Sublist,Sum]
и вызываетfoldl/4
, которая «сворачивает влево» списокSublist
, используя цель в позиции аргумента 0, начиная со значения 0 и приводя к значениюSum
. - Операция складывания — это просто арифметическое сложение с помощью
[AccumIn,X,AccOut]>>(AccOut is AccumIn X)
.
Это может быть более подробно записано как:
suma(ListOfLists,ListOfSums) :-
maplist(
p2, % will be called with 2 parameters
ListOfLists,
ListOfSums).
p2(Sublist,Sum) :-
foldl(
p3, % will be called with 3 parameters
Sublist,
0,
Sum).
p3(AccumIn,X,AccOut) :-
AccOut is AccumIn X.
Мы можем запустить несколько plunit
тестовых примеров для хорошей оценки (на самом деле, проблема, которую нужно решить, должна быть указана ниже, TDD и все такое):
:- begin_tests(sum_over_sublists).
test("empty list of lists",true(R == [])) :-
suma([],R).
test("all sublists contain one value",true(R == [1,2,3])) :-
suma([[1],[2],[3]],R).
test("one sublist is empty",true(R == [1,0,3])) :-
suma([[1],[],[3]],R).
test("standard case #1",true(R == [6,15,24])) :-
suma([[1,2,3],[4,5,6],[7,8,9]],R).
test("standard case #2",true(R == [10,14,18])) :-
suma([[1,2,3,4],[2,3,4,5],[3,4,5,6]],R).
:- end_tests(sum_over_sublists).
И так:
?- run_tests.
% PL-Unit: sum_over_sublists ..... done
% All 5 tests passed
true.
Комментарии:
1. Я также думаю, что Prolog нуждается в небольшом расширении для альтернативной работы с позиционными параметрами и именованными параметрами, чтобы можно было писать
foldl(start=0,list=Sublist,result=Sum,goal=p3)
так, как это можно делать в цепочках правил, таких как CLIPS.2. Если вы все равно переходите на SWI, вы также можете использовать его
sum_list/2
(который действительно должен вызыватьсяlist_sum/2
для отражения порядка аргументов).3. @IsabelleNewbie «Фиксирует» использование
foldl/N
?4. Да, и с помощью
library(yall)
.maplist(sum_list, Xss, Sums)
короче, чем ваше решение, и переносится, по крайней мере, на GNU Prolog. Не поймите меня неправильно, в хвастовстве нет ничегоlibrary(yall)
плохого! Мне просто показалось интересным, что в данном конкретном случае вы делаете слишком много работы самостоятельно.
Ответ №2:
%! sum(Xs,SUM)
%
% calculate the total sum of the items in list `Xs` .
sum(Xs,SUM)
:-
sum(Xs,0,SUM)
.
sum([],SUM0,SUM0) .
sum([X0|Xs],SUM0,SUM)
:-
SUM1 is SUM0 X0 ,
sum(Xs,SUM1,SUM)
.
/*
?- sum([1,2,3,4],SUM).
SUM = 10.
?- sum([2,3,4,5],SUM).
SUM = 14.
?- sum([3,4,5,6],SUM).
SUM = 18.
*/
%! suma(Xss0,SUM)
%
% calculate the total sum of the items in list of lists `Xss` .
suma([],0) .
suma([Xs0|Xss0],SUM)
:-
sum(Xs0,SUM0) ,
suma(Xss0,SUM1) ,
SUM is SUM0 SUM1
.
/*
?- suma([[1,2,3,4],[2,3,4,5]],SUM).
SUM = 24.
?- suma([[1,2,3,4],[2,3,4,5],[3,4,5,6]],SUM).
SUM = 42.
*/
Комментарии:
1. Но результат последнего примера должен быть
[ 10, 14, 18 ]
, а не42
. Вы должны суммировать по отдельным подспискам, а не по всем элементам всех подсписков.2. @DavidTonhofer что-то нужно оставить для домашней работы .