user2730833
user2730833

Reputation: 183

trying to implement get the nth element of a list in Prolog

I am very new in Prolog and trying to implement get the nth element of a list in Prolog here is my code but it throws error

element_at(X,[X|_],1).
element_at(X,[_|L],K) :-
   K > 1,
   K1 is K - 1,
   element_at(X,L,K1).

I think that X in the second line in the right side of the code has to be replaced with some thing else but I could not think of any .

Upvotes: 2

Views: 8349

Answers (2)

lurker
lurker

Reputation: 58234

Here is a tail-recursive version using an accumulator. Using the accumulator, its value is instantiated already on each call so you can increment first, then do the recursion.

element_at(X, List, Pos) :-
    element_at(X, List, 1, Pos).
element_at(X, [X|_], Pos, Pos).
element_at(X, [_|T], Acc, Pos) :-
    Acc1 is Acc + 1,
    element_at(X, T, Acc1, Pos).

This works with various combinations of variables on the input, but it (as well as CapelliC's non-tail recursive version) will loop infinitely if Pos is ground and after a possible solution is found, such as with:

| ?- element_at(X, L, 3).

L = [_,_,X|_] ? ;
.... loop ....

So a modification to check for this case avoids that:

element_at(X, List, Pos) :-
    element_at(X, List, 1, Pos).
element_at(X, [X|_], Pos, Pos).
element_at(X, [_|T], Acc, Pos) :-
    (nonvar(Pos) -> Acc < Pos ; true),  % fail if Acc hits ground Pos
    Acc1 is Acc + 1,
    element_at(X, T, Acc1, Pos).

Now you get:

| ?- element_at(X, L, 3).
L = [_,_,X|_] ? ;
no.

And:

| ?- element_at(X, L, P).
L = [X|_]
P = 1 ? ;
L = [_,X|_]
P = 2 ? ;
L = [_,_,X|_]
P = 3 ? ;
L = [_,_,_,X|_]
P = 4 ? ;
...etc...

Upvotes: 1

CapelliC
CapelliC

Reputation: 60004

K is not evaluated when you test it. You need to reverse the order

element_at(X,[X|_],1).
element_at(X,[_|L],K) :- element_at(X,L,K1), K is K1 + 1.

Upvotes: 5

Related Questions