0

I need to create a list from a knowledgebase that could look like this:

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)

That list needs to contain tuples with each containing the second and third Value of fact2, and the added numbers of fact2, whenever the first value of fact1 and fact2 match up.

Maybe it gets clearer when I show what I have so far. Here is my predicate with the findall statement, which to me seems to get me the closest to where I need to get:

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

The List I receive from this, looks like this:

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)]

But really I need the list to look like this:

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

Meaning that, whenever the first two elements of a tuple match up, the numbers, which are the third element of the tuple, should be added together.

I do not know however how to even approach something like this, as I have always read, that as soon as the list is set, it cannot be changed, since prolog is functional and declarative.

So I think I somehow need to match every element against the one before or after it (since the list will always be sortet by the Out1 and Out2 variables), and if they match, add the third value in the tuple together. The problem is, that I have no idea how.

To me it looks like this can not realy be done within the findall itself but would need to be done after the findall I am a true beginner and would appreciate any help. In this case it would be best, if the solution was all in one predicate.

repeat
  • 18,496
  • 4
  • 54
  • 166
HappyHippo
  • 152
  • 3
  • 11
  • 2
    I hate to say this, but when I see your questions I just pass them by because you never give enough details. – Guy Coder Apr 14 '19 at 13:15
  • Please use proper syntax. `fact2 (Val3, Out1, Out2)` will be a syntax error in Prolog. You cannot have any spaces between the functor and the arguments. – lurker Apr 14 '19 at 14:15

2 Answers2

0

Here is another solution that uses more than one predicate:

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.

output:

?- collect_items(Result).
Result = [[a, b, 9], [c, d, 15], [e, f, 7]].
Mario L
  • 224
  • 1
  • 11
0

with library aggregate:

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).

we get

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

You are not right here

since prolog is functional and declarative

Prolog is relational and declarative

CapelliC
  • 59,646
  • 5
  • 47
  • 90