2

I'm trying to develop code in prolog to capture items with frequency 0. Look at the example, the tuple:

[[1,31],[2,0],[3,21],[4,0],[5,0]]

Where each element is something else with 2 elements each, so the elements that should be captured are 2, 4 and 5, for frequency 0. The code below represents the idea:

match([],_).
match([[A,Y]|Tail],[A|Tail2]):- Y==0,match(Tail,[Tail2|A]),!.
match([[_,_]|Tail],X):- match(Tail,X).

Two parameters are passed: A tuple containing the set of target values and frequencies,

(["Target value", "frequency"], ["target value", "frequency"], ...]

And a second parameter that is a variable, it receives the target elements. However, the abstraction I had to develop the code is not correct, because the results are not as expected. I have gone round step by step to understand, modified several things and the result is always the same ... A list with only 2 elements is returned in any case (even if there is only one target with a frequency of 0).

Example with 3 frequency targets 0:

?- match([[1,31],[2,0],[3,312],[4,0],[5,0]],X).
X = [2|4].

Expected result for this case: X = [2,4,5].

Example with 1 frequency target 0:

?- match([[1,31],[2,0],[3,312],[4,312],[5,123]],X).
X = [2|_9998].

Expected result for this case: X = [2].

Someone can help me?

2 Answers2

2

You could opt to describe the resulting list with DCGs like so:

match(Pairs,ZFs) :-           % the items with frequency 0
   phrase(zeros(Pairs),ZFs).  % are described by zeros//1

zeros([]) -->                 % the empty list
   [].                        % contains no items
zeros([[I,0]|Is]) -->         % if the frequency is 0
   [I],                       % the item is in the list
   zeros(Is).                 % the same for the remaining items
zeros([[I,F]|Is]) -->         % if the frequency
   {dif(F,0)},                % is not 0, the item isn't in the list
   zeros(Is).                 % the same for the remaining items

Thus the two example queries in your post yield the desired results:

   ?- match([[1,31],[2,0],[3,21],[4,0],[5,0]],X).
X = [2,4,5] ? ;
no
   ?- match([[1,31],[2,0],[3,312],[4,312],[5,123]],X).
X = [2] ? ;
no
tas
  • 8,100
  • 3
  • 14
  • 22
1

You're very close! Just two little issues:

  • Currently when an empty list is passed it, you say the result can be anything (_). I highly doubt this is what you want; the output for an empty list shoudl be an empty list as well.
  • The recursive call in the second clause is not correct. What you want the result to be is A followed by the result of the recursive call (Tail2). However, for some reason you wrote the recursive call with also A in it. I can't quite tell how you got to this, but you should just get Tail2 on its own.

Additionally, you can avoid writing Y==0 by directly writing it in the head of the clause. The resulting code then looks like this:

match([],[]).
match([[A,0]|Tail], [A|Tail2]) :- match(Tail, Tail2), !.
match([[_,_]|Tail], X) :- match(Tail, X).

?- match([[1,31],[2,0],[3,312],[4,0],[5,0]],X).
X = [2, 4, 5]

?- match([[1,31],[2,0],[3,312],[4,312],[5,123]],X).
X = [2]
Steven
  • 2,437
  • 5
  • 32
  • 36
  • Wow, very thanks! I'm starting for now in the prolog and the use of recursion in logic programming is something new for me. Sometimes is so hard to understand what I must do. – Fellipe Peixoto May 08 '17 at 05:07