The answer of Daniel is very good, I just want to offer another way to look at it.
Take this trivial Prolog definition of natural numbers based on TNT (so 0 is 0
, 1 is s(0)
, 2 is s(s(0))
etc):
n(0). % (1)
n(s(N)) :- n(N). % (2)
The declarative meaning is very clear. (1) says that 0 is a number. (2) says that s(N)
is a number if N
is a number. When called with a free variable:
?- n(X).
it gives you the expected X = 0
(from (1)), then looks at (2), and goes into a "new" invocation of n/1
. In this new invocation, (1) succeeds, the recursive call to n/1
succeeds, and (2) succeeds with X = s(0)
. Then it looks at (2) of the new invocation, and so on, and so on.
This works by unification in the head of the second clause. Nothing stops you, however, from saying:
n_(0).
n_(S) :- n_(N), S = s(N).
This simply delays the unification of S
with s(N)
until after n_(N)
is evaluated. As nothing happens between evaluating n_(N)
and the unification, the result, when called with a free variable, is identical.
Do you see how this is isomorphic to your is_integer/1
predicate?
A word of warning. As pointed out in the comments, this query:
?- n_(0).
as well as the corresponding
?- is_integer(0).
have the annoying property of not terminating (you can call them with any natural number, not only 0). This is because after the first clause has been reached recursively, and the call succeeds, the second clause still gets evaluated. At that point you are "past" the end-of-recursion of the first clause.
n/1
defined above does not suffer from this, as Prolog can recognize by looking at the two clause heads that only one of them can succeed (in other words, the two clauses are mutually exclusive).