2

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).
Andrew
  • 1,839
  • 14
  • 25
  • Can you post the actual non-working code? I suspect there is something wrong with your application of failure slicing (I really don't see how non-termination could arise in the examples provided) but I can probably help debug the code without applying the technique. – Daniel Lyons Jul 07 '18 at 04:32
  • The code I posted fails to terminate for me. I get the one output, `X = x`, but it doesn't stop. I did manage to get it working, so I'll edit in what I did. – Andrew Jul 07 '18 at 06:34
  • 2
    Exactly what do you want your predicate to do? For recursing until 0, you would have a base case of `f(x, 0).` and your recursive case would be `f(X, Y) :- Y > 0, Y1 is Y - 1, f(X, Y).` or better, since you're reasoning about integers, using CLP(FD): `f(X, Y) :- Y #> 0, Y1 #= Y - 1, f(X, Y).` – lurker Jul 07 '18 at 14:32
  • 1
    "*this doesn't work either*"... what result are you expecting and what are you getting? What does the relation `int_int_prod/3` mean? – lurker Jul 07 '18 at 14:32
  • yes, `Y > 1` (or `Y #> 0`) is the analogue of `Y = [ _ | _ ]`. – Will Ness Jul 07 '18 at 17:53
  • 1
    I loaded the first fragment and it terminates on my machine (without recursion it must terminate). Have you restarted the Prolog interpreter and tried it without old code present from earlier attempts? Is the body of the first clause intended to be a unification of the variable `X` with the constant `x` (notice the different case)? In that case, it's better to write it as a fact `f(x, 0).` or to at least rename the variable for clarity. – lambda.xy.x Jul 08 '18 at 12:34
  • @lurker I added detail about what I expect and what I'm getting. The `int_int_prod` relation is from the linked question, I was just showing my research. – Andrew Jul 09 '18 at 17:28
  • @lambda.xy.x I added a description of what I expect and what I'm getting. I agree that the first clause was ugly, I rewrote it and I see the same issue. – Andrew Jul 09 '18 at 17:30

1 Answers1

2

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.
Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • 1
    Ok, so I was misunderstanding the interface. Thanks! – Andrew Jul 09 '18 at 18:21
  • 1
    @AndrewPiliser you're welcome! this really shows the importance of asking the questions on SO properly, BTW. If you'd included all the info from the outset, you'd get the answer much sooner. :) Happy trails! – Will Ness Jul 10 '18 at 06:32
  • *termination improves*: This is a very unusual use of *termination*. I'd rather say, a clause like `f(X,Y) :- false` does not change termination at all. – false Feb 08 '20 at 12:49