Search code examples
listprologinstantiation-error

Prolog: Head of a variable list is not instantated


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?


Solution

  • 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] ;
    ...