
% factorial(N, F) is true if F = N!
factorial(1,1).

% rule to apply if we are given N as an integer F as a variable
factorial(N, F) :- integer(N), N>1,
                   N1 is N-1, factorial(N1, F1), 
                   Result is N*F1, F = Result.

% rule to apply if we are given F but njot N
factorial(N, F) :- integer(F), F > 1, var(N),
                   % compute 1!, 2!, 3! etc until we N or exceed F
                   factorial(N, F, 1, 1).

% factorial(N,F,I,FI)
% -------------------
% given I and FI = I!, we're computing I!, (I+1)!, ..., N!
%    until FI = F (success) or FI > F (fail)

% base case 1, we found it
factorial(N,F,N,F).  

% base case 2, FI is too big, give up
factorial(_,F,_,FI) :- FI > F, !, fail.

% general case, try recursively on I+1 and (I+1)!
factorial(N,F,I,FI) :- NewI is I + 1, NewFI is FI * NewI,
   factorial(N,F,NewI,NewFI).

