m5signorini
m5signorini

Reputation: 25

Prolog - Find second and second last elements in list

I am new to prolog and currently stuck trying to understand how to implement this. I need a predicate to find the second and the second last elements of a list using recursion, so for example:

second_secondLast([1,2], X, Y). must return X=2, Y=1.

second_secondLast([1,2,3], X, Y). must return X=2, Y=2.

second_secondLast([1], X, Y). must print 'Error' and return false.

First, I have the error-checking clauses:

second_secondLast([], X, Y) :- print("Error"), !, fail.
second_secondLast([_], X, Y) :- print("Error"), !, fail.

Next, I tried something like this:

second_secondLast([Y,X],X,Y) :- !.
second_secondLast(L, X, Y) :-
    second(L,X),
    secondLast(L,Y).

second([_,S|_], X) :- X = S.

secondLast([P,_], Y) :- Y = P.
secondLast([F|R], Y) :- secondLast(R, Y).

However, the output using [1,2,3] is X=Y, Y=2. I'm not sure if it is possible to force the output to be X=2 instead, or if there is a better method to do this.

Upvotes: 1

Views: 284

Answers (1)

tiffi
tiffi

Reputation: 683

First of all, the output X=Y, Y=2. has nothing to do with your program, it is an idiosyncracy of swipl (and maybe other interactive environments for Prolog implementations).

I think, your program looks fine, but you are asking for possible improvements.

second([_,S|_], S). is a more elegant version of your second([_,S|_], X) :- X = S..

Likewise, secondLast([P,_], P). is more elegant than your secondLast([P,_], Y) :- Y = P..

I would also prefer secondLast([_|R], Y) :- secondLast(R, Y). to your secondLast([F|R], Y) :- secondLast(R, Y)..

Your error-checking clauses look fine to me.

You could also get rid of the predicate second and alter the definition of second_secondLast by using

second_secondLast([H,X|T], X, Y):-
   secondLast([H,X|T], Y).

instead of your

second_secondLast(L, X, Y) :-
    second(L,X),
    secondLast(L,Y).

That change would also make it a bit more efficient. Another possibility is to use

second_secondLast(L, X, Y):-
    L= [_,X|_],
   secondLast(L, Y).

Then you could also get rid of the predicate secondLast and alter the above clause to

second_secondLast(L, X, Y):-
    L= [_,X|_],
   append(_, [Y,_], L).

.

There is always a ton of possibilities...

Upvotes: 1

Related Questions