Search code examples
listprologlogictuplesparadigms

Capture values from one list in Prolog and add to another list


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?


Solution

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