Reputation:
I'm working on an example I found online, trying to understand what Prolog returns. For this code here ...
element_at(X,[X|_],1).
element_at(X,[_|L],K) :-
K > 1,
K1 is K - 1,
element_at(X,L,K1).
This works ...
?- element_at(x, [a,b,c,x,x,d,e], Pos).
But this doesn't ... I expected this code to return a list of valid values, for example ...
?- element_at(x, [a,b,c,x,x,d,e], Pos).
Pos = 4;
Pos = 5;
But instead I get ERROR: >/2: Arguments are not sufficiently instantiated
What do I change to get it to return the valid values for Pos
?
Upvotes: 1
Views: 408
Reputation: 60024
With the help of declarative arithmetic available in SWI-Prolog:
:- [library(clpfd)].
element_at(X,[X|_],1).
element_at(X,[_|L],K) :-
K #> 1,
K1 #= K - 1,
element_at(X,L,K1).
we get the expected, declarative behaviour:
?- element_at(x, [a,b,c,x,x,d,e], Pos).
Pos = 4 ;
Pos = 5 ;
false.
Upvotes: 2
Reputation:
It doesn't work like that, because, in order to make arithmetic in Prolog viable, you don't have positive integers defined as successors of 0. So for arithmetic comparisons you need both sides to be valid arithmetic expressions, and for the succ(N,N1)
predicate available in SWI (such that N1 is N+1) you need at least one of the two arguments to be instantiated.
SWI has predicates nth0/3
and nth1/3
which do exactly what you are trying to achieve (argument order is a bit different). It is implemented in Prolog, and what it does, it looks whether the N is a variable or a positive integer, and then calls either a generating nth
that returns all indices on backtracking, or a deterministic nth
that selects the N-th element.
This is copied from lists.pl in SWI-Prolog's source!
nth0(Index, List, Elem) :-
( integer(Index)
-> nth0_det(Index, List, Elem) % take nth deterministically
; var(Index)
-> List = [H|T],
nth_gen(T, Elem, H, 0, Index) % match
; must_be(integer, Index)
).
Note how nth_gen
needs to be seeded with 0, so that it can count the index of the element currently being compared.
Upvotes: 1
Reputation: 5645
If you look at your code, you see that K is initialized when x is the first element of the list. When it's not the case, K is incremented. If x was not the first element of the list when you called the predicate, K has no value !
Upvotes: 0