The reason is the ++
appends it second argument to the end of its first argument which must be a list. It does not do any processing of its second argument, it just appends it as is. So:
1> [1,2,3] ++ undefined.
[1,2,3|undefined]
2> [1,2,3] ++ [undefined].
[1,2,3,undefined]
The reason you can do this as well as:
3> [a|b].
[a|b]
4> [a|[b]].
[a,b]
is that a list is a sequence list cells, a singly linked list, not a single data structure as such. If the right-hand-sides, called the tail, of each cell is another list cell or []
then you get a proper list. The left-hand-side of each cell is called the head and usually contains the elements of the list. This is what we have in 2 and 4 above. Most, if not all, library functions assume that lists are proper lists and will generate an error if they are not. Note that you have to actually step down the whole list to the end to see if it is proper or not.
Each list cell is written as [Head|Tail]
and the syntax [a,b,c]
is just syntactic sugar for [a|[b|[c|[]]]]
. Note that the tail of each list cell is a list or []
so this is a proper list.
There are no restrictions as to what the types the head and tail of a list cell can be. The system never checks it just does it. This what we have in 1 and 3 above where the tail of the last list cell (only list cell in 3) is not a list or []
.
Sorry getting a bit over-didactic here.
EDIT: I see that I have already described this here: Functional Programming: what is an "improper list"?