# [erlang-questions] wierd list comprehension outcomes

Richard A. O'Keefe ok@REDACTED
Fri Jan 30 05:06:07 CET 2015

```On 25/01/2015, at 11:28 pm, Roelof Wobben <r.wobben@REDACTED> wrote:

> Hello,
>
> I follow this book : Erlang programming and I did read chapter 2.
>
> Now I have to do this exercise :
>
> C. Recursive list definitions
> L = [A|[2,3]].
> [[3,2]|1].
> [H|T] = L.

1. L = [A|[2,3]]

Presumably A already has a value.  What is it?

(Begin transcript.)
1> L = [A|[2,3]].
* 1: variable 'A' is unbound
2> A = 1.
1
3> L = [A|[2,3]].
[1,2,3]
(Pause transcript.)

2. [[3,2]|1].

I see no problem here.

(Resume transcript.)
4> [[3,2]|1].
[[3,2]|1]
(Pause transcript.)

Some people will tell you that there is a problem because 1 is not a list
and the tail of a list must be a list.  They are wrong.

In Erlang, one kind of term is a pair [Head | Tail],
where Head and Tail can be *absolutely any term whatever*.

The programming language Scheme distinguishes clearly between “pairs”
which can be anything and “lists” which are *made from* pairs as
building blocks: a list is empty () or a pair whose tail is a list.

Erlang has a list/1 *type* and an is_list/1 *guard test*.
is_list([]) succeeds.
is_list([H|T]) succeeds *whatever H and T are*.

http://erlang.org/doc/reference_manual/typespec.html says of types that
List :: list(Type)                           %% Proper list ([]-terminated)
| maybe_improper_list(Type1, Type2)    %% Type1=contents, Type2=termination
| nonempty_improper_list(Type1, Type2) %% Type1 and Type2 as above
| nonempty_list(Type)                  %% Proper non-empty list

so is_list([[3,2]|1]) succeeds, but [[3,2]|1] does not have type list(T)
for any type T.

Are you confused yet?  If not, why not?  I’ve always thought that is_list/1 was

We can say that ALL [_|_] TERMS ARE DOTTED PAIRS = CONS CELLS,
but ONLY SOME CONS CELLS ARE PARTS OF LISTS.

You wrote

* [[3,2]|1].

* 2: syntax error before: '['  which I expected to see also [ 1 , 2 , 3]

As the transcript above shows, there is absolutely no problem with this.
The ‘[‘ in question is presumably the first one, which tells me that there was
some junk before this line.

In any case, there is NO WAY that [[3,2]|1] could possibly give you [1,2,3].

3. [H|T] = L.

I see no problem here.

(Resume transcript).
5> [H|T] = L.
[1,2,3]
6> H.
1
7> T.
[2,3]
(Pause transcript.)

You wrote
* [H|T] = L.

Which I see ** exception error: no match of right hand side value [1,2,3]

You keep on not showing us everything relevant.  “no match” tells me that
either H already has a value that is not 1 or T already has a value that
is not [2,3].

where I was expected to see [1] [ 2, 3]

You could never have seen [1].  If you write [H|T] = [[1],2,3] _then_ you
will get H = [1] and T = [2,3] but not otherwise.

You need to be very clear about
- extending a list on the left by a single element “consing” [New_Head | Old_Tail]
- extending a list on the left by a list of many elements “appending” New_Elements ++ Old_Tail.
In particular,

(Resume transcript.)
8> [0|L].
[0,1,2,3]
9> [0] ++ L.
[0,1,2,3]
10> 0 ++ L.
in operator  ++/2
called as 0 ++ [1,2,3]

11> [[0]|L].
[[0],1,2,3]
(End transcript.)

Finally, the subject line of your message says “weird list COMPREHENSION outcomes”,
but the body of the message contains no list comprehensions whatsoever.
Did you mean “list CONSTRUCTION outcomes”?

```