Newbie question about | operator

I’m trying to learn Elixir and can’t really understand the | operator

The normal [1 | [2, 3]] makes perfect sense to me, but what is [1 | 1]?
It is ok to use [1 | 1] but it is not ok to use 1 | 1.

Also [2 , 3] ++ [1 | 1] will result in [2, 3, 1 | 1], but [1 | 1] ++ [2, 3] will fail

So what does the | operator stand for when it is part of a result of an operation?

Br Patrik

1 Like

The vertical bar is pronounced as “cons” and needs a pair of enclosing square brackets to work at all.

It is used to build a linked list.

To the left of the operator there comes the current element, while on the right there comes the remainder of the list, which is usually a list but does not need to. So each list will end eventually with either an empty list (a proper list) or any other value that is not a list (an improper list).

Whenever you write a , in a list, it is basically syntactic sugar around |. [1] is actually [1|[]], [1, 2] is [1|[2|[]]] and so on.

After what I explained so far, lets assume Kernel.++/2 were implemented as this[1]:

def ++(left, right)
def ++([], right), do: right
def ++([h|t], right), do: [h|t ++ right]

So as you can see, the shape of the right list is irrelevant, it is just appended as is when we hit the empty list on the left. That’s why [2 , 3] ++ [1 | 1] works. But as you can see as well, we need the empty list as end marker on the left. If it is not there, then it will break.

So when we do [1 | 1] ++ [2, 3] we will hit a missing clause at the first recursive call: 1 ++ [2, 3] in [1|1 ++ [2, 3]].

[1] This is just an example, the real implementation might be different but will be equivalent in its result. The difference in implementation is then mostly because of optimisations since my version is inefficient on the stack.

3 Likes

[1 | 2] is what’s called an improper list.

| is the operator that joins a head of a list with a tail: [h | t]. If t is a list, the result will be a new list with h as the first element, followed by the elements of t. If t is not a list, the operation doesn’t create a new list and you get the improper list.

1 Like

[1 | [2 | [3 | []]]] is the same as [1, 2, 3]

note the empty list at the end

now you do this:

[head | tail] = [1 | [2 | [3 | []]]]

the head of above list is 1
and the tail is [2, 3] or [2 | [3 | []]] (basically the same)

if you do this
[hd | tail] = [3]

the head is 3, the tail is empty []

[1 | 1] is improper list because it has no empty list at the end

when you do this
[hd | tail] = [1 | 1]

head is 1
tail is 1
no list is left

3 Likes