Search code examples
prolog

Prolog Predicate for positive and negative integers


I'm currently studying for an exam in Prolog and so am trying to do some sample questions to get ready. I've been trying this one for while, the task it to create intgr/1 so that

?-intgr(X).
X=0;
X=1;
X=-1;
X=2;
X=-2;
...

What I have now is

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

However, it lists them out in a really weird way, namely:

X = 0
X = 1
X = -1
X = 2
X = 0
X = 0
X = -2
X = 3 ...

I'm just wondering what a good approach would be to change that in order to get them listed out in the right order.


Solution

  • Efficient:

    intgr(I) :-
        integer(I),
        % Any integer will do, can stop here
        !.
    intgr(I) :-
        var(I),
        (   I = 0
        % Start alternating +/- with 1
        ;   intgr_(1, I)
        ).
    
    % Plus
    intgr_(N, N).
    % Minus
    intgr_(N, I) :-
        % Calc negative, rather than -(N) term
        I is -N.
    intgr_(N, I) :-
        % Increment into infinity
        N1 is N + 1,
        intgr_(N1, I).
    

    Results in swi-prolog:

    ?- intgr(-5).
    true.
    
    ?- intgr(0).
    true.
    
    ?- intgr(4).
    true.
    
    ?- intgr(fish).
    false. % Fails quickly, as appropriate
    
    ?- intgr(I).
    ?- intgr(I).
    I = 0 ;
    I = 1 ;
    I = -1 ;
    I = 2 ;
    I = -2 ;
    I = 3 ;
    I = -3 ;
    ...
    

    As @TA_intern pointed out, this can be shortened (if inf is supported in between) to:

    intgr_between(I) :-
        integer(I),
        % Any integer will do, can stop here
        !.
    intgr_between(I) :-
        var(I),
        (   I = 0
        % Start alternating +/- with 1
        ;   between(1, inf, N),
            (   I = N
            ;   I is -N
            )
        ).
    

    Counting up to infinity can be implemented as e.g.:

    incrementing_from(Start, N) :-
        integer(N),
        !,
        integer(Start),
        % Both variables are integer
        N @>= Start.
    incrementing_from(Start, N) :-
        var(N),
        integer(Start),
        incrementing_from_(Start, N).
    
    incrementing_from_(N, N).
    incrementing_from_(U, N) :-
        U1 is U + 1,
        incrementing_from_(U1, N).