In this Prolog code I intend to list the first N primes,
(...)
biggerPrime(N,P) :-
isPrime(N),
P is N,
!.
biggerPrime(N,P) :-
N1 = N+1,
biggerPrime(N1,P).
primeListAcc(0,A,R,R) :- !.
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[P|L],R).
And it works fine if I want the list ordered backwards:
?- primeList(5,L).
L = [11, 7, 5, 3, 2].
But if I change the last line of the code from [P|L] to [L|P] like this:
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[L|P],R).
I get:
?- primeList(5,L).
L = [[[[[[]|2]|3]|5]|7]|11].
What am I missing? This is driving me mad!
Great, so you've discovered the problem of adding elements to the end of a list. In Prolog, we can do it with
wait, what? How to read this? We must know the calling convention here. We expect
L
andZ
to come in as uninstantiated variables, and we arrange forL
from now on to point to a newly created cons node withX
at its head, andZ
its tail.Z
to be instantiated, possibly, in some future call.IOW what we create here is an open-ended list,
L = [X|Z] = [X, ...]
:We can see now that
Z
is not really needed here, as it carries the[]
down the chain of recursive calls, unchanged. So we can re-writeprimeListAcc
without theZ
argument, so that its final clause will beKeeping
Z
around as uninstantiated variable allows for it to be later instantiated possibly with a non-empty list as well (of course, only once (unless backtracking occurs)). This forms the basis of "difference list" technique.To answer your literal question - here, consider this interaction transcript:
the
[a|b]
output is just how a cons node gets printed, when its tail (here,b
) is not a list. Atoms, as numbers, are not lists.Recall that a list is either the empty list
[]
or a term with functor'.'
and two arguments, whose second argument is a list. The syntax[P|Ps]
is shorthand notation for the term'.'(P, Ps)
, which is a list ifPs
is a list (as is the case in your example). The term'.'(Ps, P)
, on the other hand, which can also be written as[Ps|P]
(as you are doing), is not a list ifP
is not a list. You can obtain a reverse list withreverse/2
.