0

So, I've spent a lot of my time trying to figure this out without almost no progress. Hope you could help me. The goal is, to take a list like this(lets call it baselist): [[[feesc,11],[podshare,11]],[[feesc,11]],[]]. And make it become this: [[feesc,22],[podshare,11]].

I have a predicate responsible to add or sum to the resulting list. Here is the code:

place_key([Key,Value], [], [Key,Value]).
place_key([Key,Value], [[Key,V]|Rest], [[Key,V1]|Rest]) :- V1 is V+Value.
place_key([Key,Value], [[K,V]|Rest], [[K,V]|List2]) :- Key \= K, place_key([Key,Value], Rest, List2)."

If I manually call this method, for simulating the recursion, it works exactly how I want. Example:

 place_key([feesc,11], [], R), place_key([feesc,11],R,J). 
So J is = [[feesc,22]]. 

Expected result is correct. The problem is to that with recursion.

So basically what I need to do is: iterate through the baselist, when reaching each key/par list, call place_key and keep it in the stack so the recursion keeps it until the last. Just to point out, I don't want to append, I just need the latest result from place_key.

What I have done so far:

fe([HO|T],NL,R) :- write(HO), place_key(HO,NL,RESULT), fe(T,RESULT,R).
fe(S,R):- fe(S,[],R).
fe([],[]).
feg([HO,T],R) :- fe(HO,RESULT), feg(T,RESULT), R = RESULT.
feg([],[]).

When I run:

[trace] 57 ?- feg([[[feesc,11]],[[feesc,11]]],R).
   Call: (6) feg([[[feesc, 11]], [[feesc, 11]]], _G21384) ? creep
   Call: (7) fe([[feesc, 11]], _G21484) ? creep
   Call: (8) fe([[feesc, 11]], [], _G21485) ? creep
   Call: (9) place_key([feesc, 11], [], _G21485) ? creep
   Exit: (9) place_key([feesc, 11], [], [[feesc, 11]]) ? creep //Until here, I think this is correct.
   Call: (9) fe([], [[feesc, 11]], _G21494) ? creep 
   Fail: (9) fe([], [[feesc, 11]], _G21494) ? creep
   Redo: (9) place_key([feesc, 11], [], _G21485) ? creep
   Fail: (9) place_key([feesc, 11], [], _G21485) ? creep
   Fail: (8) fe([[feesc, 11]], [], _G21485) ? creep
   Fail: (7) fe([[feesc, 11]], _G21484) ? creep
   Fail: (6) feg([[[feesc, 11]], [[feesc, 11]]], _G21384) ? creep
false.

What am I doing wrong?

Asieh hojatoleslami
  • 3,240
  • 7
  • 31
  • 45

2 Answers2

0

The problem in your case is that you don't define a base-case for fe/3. As you can see, except for your place_key predicate, you also have the following:

fe([HO|T],NL,R) :- write(HO), place_key(HO,NL,RESULT), fe(T,RESULT,R).
fe(S,R):- fe(S,[],R).
fe([],[]).
feg([HO,T],R) :- fe(HO,RESULT), feg(T,RESULT), R = RESULT.
feg([],[]).

I'll try to make this a little more readable, so you can see what's going on:

% fe/3 cases
fe([Head|Tail],Current,Result) :- write(Head), place_key(Head,Current,TempResult), fe(Tail,TempResult,Result).
% fe/2 cases
fe(S,R):- fe(S,[],R).
fe([],[]).
%% this case above is never used, as the first case always matches
% recursive and base cases for feg
feg([HO,T],R) :- fe(HO,RESULT), feg(T,RESULT), R = RESULT.
feg([],[]).

You should rewrite this as following:

fe([],Result,Result). 

This is your base case, if the list is empty, the result in-between is equal to the final result. Prolog always tries the first possible match first, so always set your base-case on top.

fe([Head|Tail],Current,Result) :- write(Head), place_key(Head,Current,TempResult), fe(Tail,TempResult,Result).

This is your recursive case, as you had before, which we will put below our base case.

We can drop the second fe/2 case, as the first case always matches and we rewrite to fe/3 anyway, which can handle all cases.

fe(S,R):- fe(S,[],R).

Below are your existing feg/2 cases. Here is also an error, because after your first fe/2-predicate, the RESULT-variable has a value, but it still needs to be able to unify with the call feq(T,RESULT), which will produce a different value. I'll leave this as an exercise.

feg([HO,T],R) :- fe(HO,RESULT), feg(T,RESULT), R = RESULT.
feg([],[]).
Snicksie
  • 1,987
  • 17
  • 27
  • 1
    OMG @Snicksie! Thx man, now I got it. Thanks for leaving the exercise as well, helped me understand better. The final code: fe([Head|Tail],Current,Result) :- place_key(Head,Current,TempResult), fe(Tail,TempResult,Result). fe([],Result,Result). feg([Head|Tail],Current,Result) :- fe(Head,Current,TempResult), feg(Tail,TempResult,Result). feg([],Result,Result). feg(S,R):- feg(S,[],R). – Pedro Ivo Rost de Borba Galimb May 06 '15 at 13:27
0

Keep your key/pairs as a tuple, a simple term with an arity of 2. Something like K-V or K:V or even tuple(K,V) is preferable to [K,V]. There's a simple reason for this:

  • K-V, K:V and tuple(K,V) all map to simple structures: -(K,V), :(K,V) and tuple(K,V) respectively, while...

  • [K,V] is syntactic sugar for a rather more complicated structure .(K,.(V,[])).

Further, you might realize that your key/value pairs are hard to distinguish from the nested list-of-lists. Keeping the Key/Value pairs as tuples makes that distincation clear.

So, let us assume your key/value pairs are represented as K:V. It sounds to me that what you're essentially wanting to do is walk your nested list-of-lists (essentially, a tree), enumerate the key/value pairs it contains and produce the set (unique). Here's one way to do that.

First, a simple predicate to identify a non-empty list:

nonnempty_list( L ) :- nonvar(L) , L = [_|_] .

Then, a simple predicate to walk the nested list of lists and enumerate each key/value pair it finds:

visit( [ K:R | Ls ] , K:R ) . % succeed if the head of the list is a key/value pair.
visit( [ L | Ls ] , KVP ) :-  % otherwise...
  nonempty_list(L) ,          % - if the head is a non-empty list ,
  visit( L , KVP )            % - visit it.
  .                           %
visit( [_|Ls] , KVP ) :-      % finally...
  visit( Ls , KVP )           % - recurse down on the tail.
  .                           %

Then you can use the magic of setof/3 to get what you want:

flattened_set( LoL , KVPs ) :-
  setof( KVP , visit(LoL,KVP) , KVPs )
  .
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135