Объединение элементов кортежей в списке в Prolog

#list #prolog #tuples #prolog-findall

#Список #пролог #кортежи #пролог-найти все

Вопрос:

Мне нужно создать список из базы знаний, который мог бы выглядеть следующим образом:

 fact1(3,3).
fact1(2,3).
fact1(3,5).
fact1(2,2).
fact1(2,10).
fact1(3,1).
fact1(1,1).
fact1(1,6).

fact2(3,a,b)
fact2(2,c,d)
fact2(1,e,f)
 

Этот список должен содержать кортежи, каждый из которых содержит второе и третье значение fact2, а также добавленные числа fact2 всякий раз, когда первое значение fact1 и fact2 совпадают.

Может быть, это станет понятнее, когда я покажу, что у меня есть на данный момент. Вот мой предикат с оператором findall, который, как мне кажется, ближе всего подходит к тому, что мне нужно получить:

 collect_items(List):-
    findall((Out1,Out2,Nr),
        (fact2(Val1,Out1,Out2),
        fact1(Val1,Nr)),
        List).
 

Список, который я получаю от этого, выглядит следующим образом:

 List = [(a,b,3),(a,b,5),(a,b,1),(c,d,3),(c,d,2),(c,d,10),(e,f,1),(e,f,6)]
 

Но на самом деле мне нужно, чтобы список выглядел так:

 List = [(a,b,9),(c,d,15),(e,f,7)]
 

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

Однако я не знаю, как даже приблизиться к чему-то подобному, поскольку я всегда читал, что, как только список установлен, его нельзя изменить, поскольку prolog является функциональным и декларативным.

Поэтому я думаю, что мне каким-то образом нужно сопоставить каждый элемент с элементом до или после него (поскольку список всегда будет сортироваться по переменным Out1 и Out2), и если они совпадают, добавьте третье значение в кортеж вместе. Проблема в том, что я понятия не имею, как это сделать.

Мне кажется, что это не может быть сделано в самом findall, но должно быть сделано после findall Я настоящий новичок и был бы признателен за любую помощь. В этом случае было бы лучше, если бы все решение заключалось в одном предикате.

Комментарии:

1. Мне неприятно это говорить, но когда я вижу ваши вопросы, я просто пропускаю их мимо ушей, потому что вы никогда не даете достаточно подробностей.

2. Пожалуйста, используйте правильный синтаксис. fact2 (Val3, Out1, Out2) будет синтаксической ошибкой в Prolog. Между функтором и аргументами не должно быть пробелов.

Ответ №1:

Вот еще одно решение, которое использует более одного предиката:

 collect_items(Result):-
    findall([Out1,Out2,Nr],(fact2(Val1,Out1,Out2),fact1(Val1,Nr)),[[OutA, OutB, N]|B]), 
    sumElements([[OutA, OutB, N]|B], Result).

sumElements([],[]).
sumElements([[Out, Outt, N]|B], [[Out, Outt, SumLocal]|RestOfList]):-
    findall([Out, Outt, X], member([Out, Outt, X], [[Out, Outt, N]|B]), SubList),
    sumLocal(SubList, SumLocal),
    subtract([[Out, Outt, N]|B], SubList, New),
    sumElements(New, RestOfList).

sumLocal([],0).
sumLocal([[_,_,S]|B], T):-
    sumLocal(B, R),
    T is S   R.
 

вывод:

 ?- collect_items(Result).
Result = [[a, b, 9], [c, d, 15], [e, f, 7]].
 

Ответ №2:

с помощью агрегата библиотеки:

 collect_items(L) :-
    setof((U,V,S),
          K^aggregate((set(X/Y),sum(N)), (
                          fact2(K,X,Y),
                          fact1(K,N)
                      ), ([U/V],S)), L).
 

мы получаем

 ?- collect_items(L).
L = [(a, b, 9),  (c, d, 15),  (e, f, 7)].
 

Вы здесь не правы

поскольку prolog является функциональным и декларативным

Prolog является реляционным и декларативным