Search code examples
integerprologpredicatefailure-slice

Predicate that generates integers and tests if integer


I'm trying to make a Prolog predicate that will let me test if a given value is a integer bigger than 0, and also give me a valid integer given a variable. It now looks like this:

intgr(1).
intgr(X) :- intgr(Y), X is Y+1.

This will generate all integers, but when used as intgr(8), it will find that it's valid, and then loop forever. Any ideas of how to solve this?


Solution

  • For generating natural numbers, you can easily write a tail-recursive (and thus more space efficient) predicate. For example:

    next_integer(I) :-
        next_integer(1, I).
    
    next_integer(I, I).
    next_integer(I, J) :-
        I2 is I + 1,
        next_integer(I2, J).
    

    But note that several Prolog compilers already provided, either as a built-in predicate or as a library predicate, the de facto standard between/3 predicate, which allows you to enumerate integers in a given interval. For example:

    ?- between(1, 3, I).
    I = 1 ;
    I = 2 ;
    I = 3.
    

    Depending on the implementation, you may also be able to use this predicate to test if an integer belongs to a given interval without leaving spurious choice points. For example:

    ?- between(1, 3, 2).
    true.
    

    Back to your question, your predicate will loop on backtracking when testing as there's nothing in it that says that the argument you pass will not be found again by continuing to add one at each pass. One solution would be to test the argument using the standard built-in predicate var/1 and cut on the first solution when the argument is bound. For example:

    next_integer(I) :-
        (   var(I) ->
            next_integer(1, I).
        ;   integer(I) ->
            next_integer(1, I),
            !
        ;   fail    % or error
        )
    
    next_integer(I, I).
    next_integer(I, J) :-
        I2 is I + 1,
        next_integer(I2, J).
    

    Hope this helps.