/* o objectivo “?- heroi(X).”*/

heroi(X) :- ajuda(X, Y), heroi(Y).
heroi(deadpool).
heroi(frodo).
ajuda(sam, frodo).


/* lista L vai ser escrita no ecrã, um elemento por linha*/
escreveLista([]).
escreveLista([H | L]) :- write(H), nl, escreveLista(L).

/*Predicado multPorN/3, tal que multPorN(L1, N, L2) é
verdade se L2 for a lista que resulta de multiplicar cada elemento da lista L1 pelo
inteiro N.*/

/*Versão iterativa*/
multPorN(L1, N, L2) :- multPorN(L1, N, L2, []).
multPorN([], _, L, L).
multPorN([H | T], N, L2, Ac) :-
    H1 is H * N,
    append(Ac, [H1], Ac1),
    multPorN(T, N, L2, Ac1).

/*Versão recursiva*/
multPorN1([], _, []).
multPorN1([H | T], N, [H1 | T1]) :-    
    H1 is H * N,
    multPorN1(T, N, T1).

/*Versão funcionais*/
multPorN2(L1, N, L2) :-
    maplist(mult(N), L1, L2).
    mult(N, E, E1) :- E1 is E*N.    

/*predicado duplicaElem/2, tal que duplicaElem(Lst1,
Lst2) significa que a lista Lst2 é o resultado de repetir cada um dos elementos da
lista Lst1.*/

/*Versão iterativa*/
duplicaElem(L1, L2) :-
    duplicaElem(L1, L2, []).
duplicaElem([], L, L).
duplicaElem([H | T], L, Ac) :-
    append(Ac, [H, H], Ac1),
    duplicaElem(T, L, Ac1).

/*Versão recursiva*/
duplicaElem1([], []).
duplicaElem1([H | T], L) :-
    duplicaElem1(T, Dup),
    L = [H, H | Dup].

/*Versão funcionais*/
duplicaElem2(L1, L2) :-
    findall([E, E], member(E, L1), LAux),
    flatten(LAux, L2).