4
votes

I'm writing a simple code generating a simple list with 5 numbers whose first variable should be positive and I'm trying to understand why this code fails

test([H|T]) :- H > 0, length(T,4).

when I call with

 length(X,5), test(X).

it shows me the following error:

ERROR: Arguments are not sufficiently instantiated

When I debug the code, the H variable in test isn't instantiated.

Anyone know why?

1
How can it even know it should be a number? - Eugene Sh.
try the query length(X, 5).. - Will Ness
length(X, 5) gives you a list of... well.... length 5, but whose elements aren't known yet. So they're variable. length/2 doesn't generate the actual elements. - lurker
You get an instantiation error for the same reason that, simply, H > 0 gives you one. - Wouter Beek
in other words, try the query H > 0. at your Prolog prompt. H is not instantiated because you have not instantiated it to anything yet. But if you do e.g. H = 3, H > 0., or H is 1 + 2, H > 0., then it works. see also stackoverflow.com/tags/instantiation-error/info. - Will Ness

1 Answers

5
votes

The issue here is that your rule for test([H|T]) doesn't describe in Prolog that H is a positive integer. It only tests if H > 0, which fails since H has not instantiation. Just attempting to compare an uninstantiated variable with a number (H > 0 in this case) doesn't cause Prolog to assume you intended H to be a number, and further, doesn't instantiate H.

Further, your rule for test/1 doesn't describe the rest of the list (T) other than to force that it be length 4. Since you're query establishes the rule that the length of the original list be 5, this stipulation is redundant.

You appear to be wanting to define test(L) such that it means L is an arbitrary list of positive integers. This is generally done using CLP(FD):

:- use_module(library(clpfd)).

test(X) :- X ins 1..10000.

This rule says that X is a list whose values are in the range 1 to 10000. The appropriate query to generate the lists of length 5 would then be:

?- length(X, 5), test(X), label(X).
X = [1, 1, 1, 1, 1] ;
X = [1, 1, 1, 1, 2] ;
X = [1, 1, 1, 1, 3] ;
X = [1, 1, 1, 1, 4] ;
X = [1, 1, 1, 1, 5] ;
...

If you want to restrict it further and say that elements need to be unique, you can use all_different/1:

test(X) :- X ins 1..10000, all_different(X).

?- length(X, 5), test(X), label(X).
X = [1, 2, 3, 4, 5] ;
X = [1, 2, 3, 4, 6] ;
X = [1, 2, 3, 4, 7] ;
X = [1, 2, 3, 4, 8] ;
X = [1, 2, 3, 4, 9] ;
X = [1, 2, 3, 4, 10] ;
...