First, your version does not even work for 1
or 2
as you suggest. And there is 0
, too. You get answers, but you have not asked for the next answer:
?- factorial(1, F).
F = 1
; error(instantiation_error,(is)/2).
So what to do to localize the problem? I will throw in a false
:
factorial(1, 1).
factorial(X, Y) :-
factorial(A, B),
Y is B * X, false,
A is X-1.
?- factorial(2, Y).
error(instantiation_error,(is)/2).
Still same problem. So it must be this very (is)/2
which is the culprit.
Let's pull the false
even further:
factorial(1, 1) :- false.
factorial(X, Y) :-
factorial(A, B), false,
Y is B * X,
A is X-1.
There are two remarkable things now: This fragment always loops! And it should be evident why: There is nothing between the head and the recursive goal. Such a situation is called left recursion.
And then there is something else that is remarkable: factorial(A,B)
is called with two uninstantiated variables! So add this A is X-1
goal in between, and further ensure that A > 0
. And add the case for 0.
Some inevitable ceterum censeo: Consider to learn arithmetics with library(clpfd)
instead. (is)/2
is soo 1970s. See the manual for more! See Reversible numerical calculations in Prolog
strike throughshadow upon the remaining part of a rule. In this manner you can best observe: Which occurrence a variable is etc. – false May 30 '14 at 23:02