Archive for April 22, 2011

Introduction to Erlang : List Comprehension

This entry is part 13 of 16 in the series Introduction to Erlang

List Comprehension

Do you remember the lists:map/2 and lists:filter/2 functions from the previous post? If not, consult the Lists & lists Module post. lists:map(Function, List) returns a new list that results from List after applying the Function to each element. lists:filter(Predicate, List) returns a list that contains only the elements of List for which the call to Predicate returns true.

Both the aforementioned operations are commonly used, as well as their combination; map & filter (does it remind you map & reduce?). Erlang provides this combined functionality using the list comprehension construct.


A list comprehension look like the following:

[Expression || Generators1, Guards1, Generators2, ...]

As their name suggests, generators create the data used in the filter-map operations. A generator has the Pattern <- Data format, where Data is a list or an expression that results to a list and Pattern is a pattern used to match with the elements of the list. This pattern can be used to disassembly elements. For example, two valid generators are I <- lists:seq(1, 10) and {X, Y} <- [{'A', 'Excellent'}, {'B', 'Good'}, {'C', 'Fair'}].


The expression specifies the elements of the result. For example, [I || I <- [1, 2, 3]] returns the input list element as is.


Guards are expressions that return either true or false, the same as the guards we have seen in the previous posts. They apply to the variables that are on the left of the guard and the ones that are accessible due to the scope where the comprehension runs. For example, I <- [1, 2, 3, 4], I rem 2 == 0 is a valid generator - guard combination (the result should be obvious; only the even numbers "pass" the guard's test).
Read the rest of this entry »