A first attempt to write a program to compute the length of a list would look as follows.
length([],0). length([H,T],N) :- length(T,M), N = M+1.
If we run this program, we get a somewhat surprising result.
?- length([1,2,3,4],N). N=0+1+1+1+1
This is because = signifies unification, not equality. Thus, when the base case is reached--that is, length(T,M) with T equal to the empty list--M is assigned 0. The phrase N=M+1 unifies N with M+1 and sets N to the expression 0+1. As the program pops out of each level of recursion, an extra +1 is added, resulting in the final expression that we saw above.
To match arithmetic expressions based on their value, Prolog provides the connective is. Thus, length should be defined as follows.
length([],0). length([H,T],N) :- length(T,M), N is M+1.
Now, the query length([1,2,3,4],N) behaves as we would expect.
?- length([1,2,3,4],N). N=4
Here is a more convoluted version of length.
length(L,N) :- auxlength(L,0,N). auxlength([],N,N). auxlength({H,T],M,N) :- auxlength(T,M1,N), M1 is M+1.
Consider what happens when we ask for
?- length([0,1,2],N)
The goals generated are
auxlength([0,1,2],0,N) -> auxlength([1,2],1,N) -> auxlength([2],2,N) -> auxlength([],3,N) -> auxlength([],3,3)
so Prolog reports back that
N = 3.
Observe the role played by unification--the variable N is being propagated through all the subgoals and the final substitution works its way back to the original query.