How to verify which items on the list meet a certain condition?

Asked

Viewed 869 times

5

How to make a call function LinhasLongas, which receives 2 parameters at least, to decide whether a bus line is long or not?

The data is in a list of punctuated pairs, such as:

((1 . 2)(2 . 3)(5 . 3)(2 . 7)(10 . 20))

Line number in the example is 1 of the first pair scored, and how many points has the line is 2 of the first pair scored.

It needs to result in a list of points that have a number of points larger than the parameter passed. Suppose there is a function called maior, who receives a and b and returns if a>b.

  • 1

    But is it Lisp or Prolog? Or do you want to do both? (and in that case, it would be better to ask two questions, right? ) By the way, your biggest problem is in reading the data in this specific format, in the logic of the function itself, or both? Already have something ready? This question seems a little wide, but I can try to answer something (in Prolog, I don’t know in Lisp).

  • Prolog, in both,n have nd ready!

  • 1

    This input format is quite strange... Is this some exercise or something like that, or is it a practical problem? In this related question I explain how to read arbitrary format data from an input or stdin file (using DCG), I would just have to adapt. As for the function itself, I will give an answer.

  • a college exercise, nothing complicated or that requires many validations. Just to get a general idea of Prolog. I’m having trouble thinking .

  • Ok. Reading and writing in Prolog is really boring... But I’m leaving it out of the answer, otherwise it gets too wide. As for function logic, the answer I’m writing uses member/2, if you don’t know this built-in I suggest (to reinforce your learning) try to implement this predicate yourself. member(?X,?L) succeeds if the first argument X is any element of the second argument L (a list).

1 answer

1

Prolog uses an execution strategy called in-depth search with setback. This means that given two calls, he will try to find a solution for the first, then one for the second, and if for some reason the second fails he "undoes" what he has done so far and tries to find some another solution for the first call, trying again the second, etc., until he finds some solution or concludes that there is no.

Thus, given the built-in member/2 (which succeeds if the element X is on the list L) and the function maior/2 which - as stated in the question - receives A and B and succeeds if A > B (note: "succeeds", not "returns"; Prolog has no functions, has relations, so that strictly speaking a Prolog relation does not "return" anything) we have:

?- L = [[1,2], [2,3], [5,3], [2,7], [10,20]], member([Linha,Pontos], L), maior(Pontos, 3).

What the Prolog engine will do is this:

  • The first member of L is [1,2], then [Linha,Pontos] = [1,2]; that is to say, Linha = 1 and Pontos = 2;
  • maior(2, 3) will fail; the setback "will disunite" Linha and Ponto, returning them to be free variables;
  • The next member of L is [2,3], then [Linha,Pontos] = [2,3]; as before, maior(3,3) will fail and the setback will occur again;
  • The next member of L is [5,3], then [Linha,Pontos] = [5,3]; as before, maior(3,3) will fail and the setback will occur again;
  • The next member of L is [2,7], then [Linha,Pontos] = [2,7];
  • maior(7,3) will succeed. As is the last call, the entire expression will have successfully completed, and what will be returned is:

    Linha = 2
    Pontos = 7
    

If you ask for "more results" (; on the command line) then it will do the rewind, trying the pair [10,20] (that will succeed) and returning it. If you ask for "more results" again, as there is no more element in the list it will return no (or false, depending on the implementation).

Okay, but what if you want not a result but all the results? Therein comes the built-in findall/3: it establishes a "target" variable, a predicate to be tested, and unifies the third argument with the list of values for that variable that satisfy the given predicate. Example:

?- findall(Linha, (
       L = [[1,2], [2,3], [5,3], [2,7], [10,20]], member([Linha,Pontos], L), maior(Pontos, 3)
   ), Lista).

Lista = [2,10]

?- findall(Linha, (
       L = [[1,2], [2,3], [5,3], [2,7], [10,20]], member([Linha,Pontos], L), maior(Pontos, 2)
   ), Lista).

Lista = [2,5,2,10]

In other words, what the findall does is more or less the same as you making a query and asking for "more results" until you have no more, and put together a list with any expression involving each result.

In conclusion, assuming you have a way to read your entry and turn it into a pair list (in this related question i give an answer showing a way to do this, via DCG), what remains then is to encapsulate the above logic in a separate relation:

lista_maiores(L, Valor, Maiores) :-
    findall(Linha, (member([Linha,Pontos], L), maior(Pontos, Valor)), Maiores).

?- lista_maiores([[1,2], [2,3], [5,3], [2,7], [10,20]], 2, Lista).

    Lista = [2,5,2,10]

Example in the ideone.

  • P.S. Now that I realize you wanted the function to be called LinhasLongas. In Prolog, anything that starts with a capital letter or a underscore (_) is a variable, so it is not possible to have a function with that name (unless you do some "gambiarra" using reflection - type using =.. and assert - and another similar gambiarra at the time of calling the function...).

  • our very much ,thank you! has given up to have an idea of how to do!!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.