What can you do with improper lists?

A proper list is a list that ends in an empty list, such as:

[1, 2, 3] (which is syntactic sugar for [1 | [ 2 | [3 | [] ] ] ] )

An improper list is a list that does not end with an empty list. An example:

[1, 2 | 3] (which becomes [ 1 | [ 2 | 3 ] ] but cannot be rewritten further).

I’ve seen multiple resources (such as The wonderful Elixir in Action book and this question on StackOverflow) state that “many of the list-related functions do not work on them, but there are some cool things you can use them for.”

What cool things are hinted at? When are improper lists useful?

2 Likes

Deeply burried in Weird SASL lists and can I rely on Kernel.is_list? there is some of the cool stuff you can do mentioned and explained.

Since I’m on mobile right now I have trouble to do better linking than the hole thread…

2 Likes

I don’t recall ever using it myself. I’d say it’s rarely called for. One example that comes to mind is saving a bit of memory. A pair represented as an improper list is smaller than with tuple:

iex> :erts_debug.size([1|2])
2

iex> :erts_debug.size({1,2})
3

So consequently, if you need to construct a bunch of pairs, you might save 1 word per pair. Note that for larger tuples (size >= 3) this won’t hold, and improper lists will in fact consume more memory.

Another example, which is mostly interesting in Erlang is simulating lazy lists (see here, the “Infinite Lists” example).

These are the only cases I can think of, so I’d say the usage is quite limited. I’d probably consider improper list only to save memory in some special cases, but I’d need very good reasons to go down that road. Since improper list could obscure the code, by default, I’d go for plain tuples.

6 Likes

Here’s a link to where the discussion turns to improper lists.

4 Likes