Manipulate list and add list items in Prolog

Asked

Viewed 2,956 times

1

I’m a beginner in Prolog and I have doubts about the list manipulation and the sum of its items.

I have a predicate historico(RA,[i1,i2,i3,...,in]) where ra is the Academic Record of a student and each i is an item, with the shape item(CM,SM,AN,NT,FQ), whereas CM is the code of the course, SM is the semester, AN is the year, NT the note, and FQ the frequency.

In addition, the predicate curriculo(Codigocurso,[i1,i2,...,in]) where each i is the code of a subject, shows us the subjects of each course.

The predicate materia(Codigomateria,Nomemateria,Creditosmateria) shows how many credits each subject has in its third parameter.

Suppose I have the following facts:

historico(08080808,[item(1,1,2008,3.0,0.77),item(1,2,2008,6.5,0.90),item(5,1,2009,8.0,0.80)]).

materia(1,algoritmos_e_programacao_para_computadores_1,4).

materia(2,paradigmas_de_programacao,4).

materia(3,programacao_orientada_a_objetos,4).

curriculo(1,[1,2,3]).

I want to do a function that checks the percentage of credits already done by a certain student. For that, I will have the function porcentagemcreditos(RA,Codigocurso,Porcentagemjacumprida).

I first need to add the credits of all the courses of the student (considering the subjects present in the curriculum), but I do not know how to add the items of a list so that I have the total credits of a course.

In addition, the function porcentagemcreditos should disregard subjects that are extracurricular, that is, if he has taken any course that is not on his course curriculum.

To put it in context, I have the following rules that I’ve already created, but I don’t think they’ll be necessary, just the rules that I’ve already mentioned:

curso(CODIGOCURSO,NOMECURSO).

materia(CODIGOMATERIA,NOMEMATERIA,CREDITOSMATERIA).

curriculo(CODIGOCURSO,[CODIGOMATERIA1,CODIGOMATERIA2,...,CODIGOMATERIAn).

aluno(RA,NOME).

cursa(RA,CODIGOCURSO).

historico(RA,[ITEM1,ITEM2,...,ITEMn).  (como mostrei anteriormente).

pertence_curso(M,C):-curriculo(C,Lista),member(M,Lista).

1 answer

1


Prolog arithmetic is based on the predicate is/2: the right side needs to contain a concrete expression (i.e. cannot have free variables), which will be evaluated and the result unified with the left side.

Therefore, a [naive] function to add items from a list would be like this:

somar([], 0).
somar([elemento(_,_,N,_,_)|R], Total) :-
    somar(R, Subtotal),
    Total is N + Subtotal.

Where elemento(A,B,C,D,E) is only an example, and you are interested in adding the Cs.

The above function can be rewritten to have tail recursion (and thus be more efficient, consuming a constant amount of memory):

somar(Lista,Resultado) :-
    somar(Lista, 0, Resultado). % zero é o valor inicial

somar([], Acc, Acc). % Se a lista acabou, retorne o que foi acumulado até então
somar([elemento(_,_,N,_,_)|R], Acc, Resultado) :-
    NovoAcc is Acc + N,
    somar(R, NovoAcc, Resultado).

(The variable Acc is an "accumulator", which will receive the values added until then and - when the recursion ends - will correspond to the final result. It can be seen as a "subtotal", but the name "accumulator" is widely used in Prolog, so it’s good that you familiarize yourself with it)

To do the function porcentagemCreditos that you want, will be necessary the following things:

  1. Get all course materials and add up your credits. Your curriculo/2 gives you the code list of course subjects, so that you can adapt the function somar above to get each matter code, consult your total credits on materia/3 and use this value in the sum;

  2. Get all the courses taken by the student and add up their credits. Again, you can adapt the somar above to iterate over the student history items, except that in this case you will "skip" the subjects that are not part of the course:

    ...
    somar_historico(Curso, [item(M,_,_,N,F)|R], Acc, Resultado) :-
        pertence_curso(M, Curso),
        passou(N,F), % Exemplo: o aluno só ganha créditos se passou, certo?
        !,
        materia(M,_,Creditos),
        NAcc is Acc + Creditos,
        somar_historico(Curso, R, NAcc, Resultado).
    % Se a matéria não fazia parte do curso, ou o aluno não passou, salta esse item
    somar_historico(Curso, [_|R], Acc, Resultado) :-
        somar_historico(Curso, R, Acc, Resultado).
    
  3. Divide one by the other. Again, using is and the division operator / (or multiplication by 100 via * and entire division via //, depending on how you want the result).

  • In the first function of summing, for example, I did not understand what "|R" means in "[element(,,N,,)|R]". For example, how I would test in Swi-Prolog the following function: > add([element(,,N,,)|R], Total). I didn’t understand how to pass to the function the list of elements.

  • A Prolog list is a chained list, with a head (the 1° element) and a tail (the remaining sublist). Example: [1,2,3] is the same as [1|[2|[3|[]]]]. Therefore, a recursive call in a list handles the first element and then the "rest of the list", until it reaches the empty list []. [Primeiro|Resto]. As for the example, try first to make a function that sums only numbers, then modify it to accept compound terms (for example, the history items). Ex.: ?- somar ([item(1,2), item(2,3), item(1,5)], Total). Choose which index you want to add.

Browser other questions tagged

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