For comprehension in Elixir

Dario Di Pasquale
4 min readDec 21, 2022

--

Photo by Wolfgang Hasselmann on Unsplash

The for comprehension is a powerful language construct in Elixir that allows developers to express complex iterations and conditional logic in a declarative way. It is quite similar to the for loop of other programming languages, but with more functionality and more concise syntax. It is used to filter and transform collections of data and can be used as an alternative to recursive functions or nested Enum functions. Personally, I find it very interesting and readable given its declarative nature.

At a high level, a for comprehension consists of a sequence of generators, filters, and collectors. Each generator represents a sequence of values, and the comprehension iterates over these sequences in a nested way. Filters allow you to specify conditions that must be met for a value to be included in the final result. If the condition of the filter evaluates to true, the value is passed to the collector. Lastly, collectors specify how the values should be combined and transformed.

Here is the basic pipeline that shows that a value gets generated from the generator, filtered by the filter and, eventually, collected by the collector.

Here is a basic example of a for comprehension that filters a list of numbers to only include even numbers:

For Comprehension

In this example, the generator is n <- numbers, which specifies that the for comprehension will iterate over the numbers list. The filter is n rem 2 == 0, which specifies that the comprehension will only include elements n for which the remainder when n is divided by 2 is equal to 0. The do: keyword specifies the transformation that should be applied to each element that satisfies the filter. In this case, the transformation is the identity function, so the element is returned unchanged.

It’s also possible to specify multiple generators in a single for comprehension. In this case, the comprehension will iterate over the Cartesian product of the generators. In the following example we use two generators:

For Comprehension — 2

Filters can also be specified for each generator. For example:

For Comprehension — 3

In addition to filtering and transforming elements, for comprehensions can also be used to perform side effects. For example, the following code snippet will print each element of the numbers list:

For Comprehension — 4

It’s also possible to bind the result of a for comprehension to a variable using the into keyword. For example:

For Comprehension — 5

Passing uniq: true can guarantee that the results are only added to the collection if they were not returned before. Here is an example of the uniq keyword:

For Comprehension — 6

The :reduce option, instead, allows us to implement a reduce step. It takes an accumulator and the do block that uses -> clauses:

For Comprehension — 7

When the :reduce keyword is given , its value is used as the initial accumulator and the do block must be changed to use -> clauses, where the left side of -> receives the accumulated value of the previous iteration and the expression on the right side must return the new accumulator value. Once there are no more elements, the final accumulated value is returned. If there are no elements at all, the initial accumulator value is returned.

In conclusion, for comprehensions are a convenient and expressive way to iterate over and transform collections of data in Elixir. They can be used as an alternative to recursive functions or nested Enum functions, and offer a clear and concise syntax for specifying complex iterations and conditional logic.

--

--