Search code examples
prologfailure-slice

How can I avoid nontermination with an integer base case?


I want to write a predicate that recurses until 0, but it consistently fails to terminate. I used failure-slicing to narrow it down to this:

f(a, 0).
f(b, 0).
f(X, Y) :- false.

When I load the file as swipl -f test.pl, then run f(X, 0). in the prompt, I get the output X = a but I don't see X = b or get a new prompt. I expect it to act like A is 1 + 1, where I get A = 2. with a period and a new ?- prompt.

I was able to get it working with something like this, but it doesn't seem clean:

f(X, 0) :- X = x.
f(X, Y) :- Y == 0 -> false; (NewY is Y - 1, f(X, NewY)).

For a list, I could write the more general case as f(X, [A|B]) to ensure that it only applies when the list has at least one element. Is there something similar I can do to ensure that the more general case here only applies when Y is not 0?

I've looked at this question, and while it hints at the right direction, this doesn't work either:

:- use_module(library(clpfd)).

int_int_prod(_, 0, 0).
int_int_prod(Num1, Num2, Result) :- 
    Num2 #> 0,
    NewNum2 #= Num2 - 1,
    int_int_prod(Num1, NewNum2, NewResult),
    Result #= Num1 + NewResult.

?- int_int_prod(0, 0, X).

Solution

  • Running f(X,0), you get X = a back. Notice the white space. The system awaits your command.

    If you press ; on the keyboard, it responds with X = b . Is this something you don't want to happen? (another option is: pressing .). After all, your definition does admit two solutions to that query, X=a and X=b. Why should Prolog skip the second one? It shouldn't.

    Another thing is, it still waits (tested in SWI, loaded from the prompt via [user]) for the user response after the second result. To eliminate that, just remove the third clause. It is entirely superfluous anyway: failing explicitly achieves the same affect as failing when no more matching clauses can be found.

    Without the third clause, f(X,Y) :- false., the termination improves:

    6 ?- f(X,0).
    X = a ;
    X = b.
    %   ^^    no white space, no waiting, immediate termination.