Reputation: 69
One thing I don't understand is why must we declare another variable during recursion. For example:
fact(0,1).
fact(N,M):- N>0, N1 is N-1, M is M1 * N, fact(N1, M1).
Why can't we just do:
fact(0,1).
fact(N,M):- N>0, M is M1 * N, fact(N - 1, M1).
On certain recursions, the latter will give a stack overflow error. What is the difference between the 2?
Upvotes: 0
Views: 49
Reputation: 1005
If you're used to Lisp -- or almost any "conventional" programming language -- you need to explicitly quote things to prevent them from being executed. Prolog is the opposite: everything is implicitly quoted and you need to explicitly mark things that are executable, either by them being a goal or by being the argument to a predicate that interprets (evaluates) them.
So, let's look at your 2nd clause:
fact(N,M):-
N>0, % 1
M is M1 * N, % 2
fact(N - 1, M1). % 3
In item #1, N>0
(which is the same as '>'(N,0)
) is in an executable context (a goal on the right-hand side) and therefore the predicate '>'/2
is called (more on this later).
In item #2, M is M1 * N
is the same as is(M, '*'(M1,N))
... the is(...,...)
is in an executable context but the M1*N
is not: it's just a structure (or "term"). The is/2
predicate interprets the 2nd argument and unifies the result with the 1st argument.
In item #3, it's similar -- equivalent to fact('-'(N,1), M1)
-- and the '-'(N,1)
is a structure that isn't interpreted further. So, N-1
will be passed as an uninterpreted argument (the N1
will, of course` be whatever value that it's been instantiated to).
Now, the confusing part is that the '>'/2
predicate interprets its arguments. So, if it gets called, for example, with 1+2 > 0
, it interprets the 1+2
(resulting in 3
) and also the 0
(resulting in 0
) and then does the comparison.
Here's another way of defining fact/2
, which might make things clearer:
fact(N, 1) :- 0 is N . % Need is/2 to force evaluation of N
fact(N, Fac) :-
N > 0, % evaluates N
fact(N-1, F0), % does *not* evaluate N-1
Fac = N*F0. % does *not* evaluate N*F0 ... Fac is N*F0 would evaluate
And this query:
?- fact(3,X), X2 is X.
X = 3*((3-1)*((3-1-1)*1)),
X2 = 6 .
You might find it instructive to try the query trace, fact(2,X)
; and also change the last goal (Fac = N*F0
) to Fac is N*F0
.
Upvotes: 1