Reputation: 1851
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).
Upvotes: 2
Views: 123
Reputation: 71074
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.
Upvotes: 2