3 Lists and Simple Data
In the section on lists, we gave an example of building a list using the
> (lists:map (lambda (x) (trunc (math:pow 3 x))) '(0 1 2 3)) (1 3 9 27) >
This sort of approach should be familiar to many programmers, even those who aren't adepts at functional programming. This is a well-known pattern. Erlang offers another pattern, though: comprehensions.
LFE supports Erlang comprehensions via two macros:
lc for list
bc for bitstring comprehensions.
3.3.1 List Comprehensions
Let's take a look at an example and then discuss it. Here's a list
comprehension version of our
lambda combo above:
> (list-comp ((<- x '(0 1 2 3))) (trunc (math:pow 3 x))) (1 3 9 27) >
This can be translated to English as "the list of integers whose values are
x raised to the power of
x is taken from the list we
provided, iterated in order from first to last."
In Erlang, this would have looked like the following:
1> [trunc(math:pow(X,3)) || X <- [0,1,2,3]]. [0,1,8,27] 2>
As we can see, the LFE syntax is not as concise as the native Erlang syntax, though it is pretty close. Our original example is 62 characters long; the LFE list comprehension is 49 characters long; the Erlang version is 41 characters.
To a Lisper, the original is probably much more legible. However, in Erlang these is no question that the list comprehensions are shorter and easier to read than using anonymous functions.
The story changes somewhat one we need iterate over several lists, such as when calculating permutations. Using the functional approach, we end up with nested anonymous functions (or nested function calls), and this gets cumbersome with dimensions greated than one.
Here's a list comprehensions that finds all the combinations of two sets of numbers:
(list-comp ((<- x (lists:seq 0 4)) (<- y (lists:seq 0 5))) (list x y))
It's just as easy if we want to add more dimensions:
(list-comp ((<- l (lists:seq 0 3)) (<- m (lists:seq 0 4)) (<- n (lists:seq 0 5)) (<- o (lists:seq 0 6))) (list l m n o))
3.3.1 Bitstring Comprehensions
For binary data, we have something similar to the list comprehension. Here's what a bitstring comprehension looks like (adapted from the example given by Francesco Cesarini and Simon Thompson in their book, "Erlang Programming"):
> (binary-comp ((<= (x (size 1)) (binary (42 (size 6))))) ((bnot x) (size 1))) #B((21 (size 6))) >
Note that the bitstring comprehension uses the
<= operator (not to be
confused with the
=< equality operator!) instead of the
list comprehensions use.
Here's the Erlang version:
2> << <<bnot(X):1>> || <<X:1>> <= <<42:6>> >>. <<21:6>> 3>
As we might expect, the native Erlang version is much more concise. Fortunately, though, in LFE we don't need to enter the whole binary form, just the bit syntax portion. In other words, instead of writing this:
(binary (x (size 1)))
(binary ((bnot x) (size 1)))
we only had to write this:
(x (size 1))
((bnot x) (size 1))