user550738
user550738

Reputation:

why isn't this prolog function returning all valid values? (Arguments are not sufficiently instantiated)

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

Answers (3)

CapelliC
CapelliC

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

user1812457
user1812457

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

joel76
joel76

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

Related Questions