Search code examples
prologinstantiation-error

Instantiation error in argument 2 of (>)/2


So im trying to define natural numbers so far i did this:

 1 nat(0).                        % 0 zero is a natural, can be a stoping case
 2 nat(X):- 0>X , !,fail.         %if is less then zero then its not a natural.
 3 nat(X):- nat(Z), X is Z+1.     %if its bigger than zero do recursively for the number-1   

When i do this it gives me "Instantiation error in argument 2 of (>)/2", so he can't instantiate X in line 2 but if take out the fail he does the comparation (>) fine and has no problem instantiating X , so why he complains if i put the fail?


Solution

  • If you want to generate natural numbers, you can do it without using cuts or the fail/0 control construct. For example:

    nat(Nat) :-
        next_integer(0, Nat).
    
    next_integer(I, I).
    next_integer(I, K) :-
        J is I + 1,
        next_integer(J, K).
    

    Sample call:

    | ?- nat(Nat).
    
    Nat = 0 ? ;
    Nat = 1 ? ;
    Nat = 2 ? ;
    Nat = 3 ?
    ...
    

    But this predicate will not work if instead you want to test if a term is a natural number. For example, the following call will result in a stack overflow in most Prolog systems (as we cannot generate a negative integer by incrementing from zero):

    | ?- nat(-3). 
    

    If you are using a Prolog system providing a CLP(FD) library, you can use a better definition:

    nat(Nat) :-
        Nat #>= 0,
        next_integer(0, Nat).
    
    next_integer(I, I).
    next_integer(I, K) :-
        J is I + 1,
        next_integer(J, K).
    

    And then use the same predicate for generating and testing. For example, using SWI-Prolog and library(clpfd):

    ?- nat(Nat).
    Nat = 0 ;
    Nat = 1 ;
    Nat = 2 ;
    Nat = 3 
    ...
    
    ?- nat(-3).
    false.
    

    Without using a constraints library, you will need to write something like:

    nat(Nat) :-
        (   var(Nat) ->
            next_integer(0, Nat)
        ;   integer(Nat), Nat >= 0
        ).