We are a software consultancy based in Berlin, Germany. We deliver
high quality web apps in short timespans.

Upstream Agile GmbH

Programming Erlang 3: funs, list comprehensions, guards, records, if/case

July 28, 2007 by alex

I started reading the book Programming Erlang and while I read I blog along what I find most interesting/important. In the end, this will hopefully be some kind of erlang tutorial, for your pleasure and my reference. :) I also started creating an Erlang Cheat Sheet with all the syntax on it. Here are the previous posts and now comes the third:

funs

Funs are anonymous functions. Funs can be assigned to variables and, more importantly, passed as arguments into functions and also be returned by functions - these would be called higher order functions.

1> Double = fun(X) -> X * 2 end.
2> Double(2).
4

One of these higher order functions is lists:map. It takes a list and a fun and applies that fun to every element of the list, returning again a list with the results. This way we could rewrite our list processing example from the previous post like this:

1> List = [1,2,3].
2> lists:map(fun(X) -> X*2 end, List).
[2,4,6]

The implementation of map is also pretty easy:

map(_, []) -> [];
map(Fun, [H|T]) -> [Fun(H) |  map(Fun, T)].

List comprehension

List comprehensions are a special construct for processing lists. They take an expression and one or more generators and filters.

1> List = [1,2,3].
2> [X*2 || X <- List].
[2,4,6]

X * 2 is the expression. It is applied to every element returned by the generator X <- List which simply pulls all the elements from the list.

A filter would, well, filter elements before handling them over to the expression:

1> List = [1,2,3].
2> [X*2 || X <- List, X > 1].
[4,6]

Here, the filter X > 1 removed the first element from our list.

Guards

Guards are a kind of extension to pattern matching in that they are more powerful. One way to use them is for defining functions:

1> greater_than_5(X) when X > 5 -> true,
1> greater_than_5(X) -> false.
2> greater_than_5(10).
true

Guards can also be used at any place you would use an expression, where they evaluate to either true or false. By the way, true and false are nothing more than atoms, so nothing special about them. Erlang knows about the difference between true and false, though. :)

You can also chain guards together. Separated by semicolons you then have a guard sequence, which ORs all the guards. If you use commas instead, Erlang ANDs all the guards.

1> true; false.
true
2> true, false.
false

The above doesn’t actually work. Line gives a syntax error - I don’t know why. Anyone? (Hey book, tell me.) Anyway, you can also use boolean expresion:

1> true or false.
true

Records

Records are some syntactic sugar above tuples. Now you can name the elements instead of having to remember their positions. First you have to define the record:

-record(book, {
  title,
  price,
  status = new
}).

Here we define a record Book with three fields title, price and status where status is set to "new" by default. (Note: record definitons can’t be typed into the shell but must be included into modules.)

Now we can create a record like this:

1> MyRecord = #book{title = "Programming Erlang", price = 19.99}.

#book{title = "Programming Erlang", price = 19.99, status = new}

To update do this:

2> MyRecord2 = MyRecord#{status = old}.

#book{title = "Programming Erlang", price = 19.99, status = old}

The above code actually creates a copy and leaves the original untouched. To read from a record we again use our precious pattern matching:

3> #book{title = Title} = MyRecord.

4> Title.
"Programming Erlang"

.. or simpler:

5> MyRecord#book.title.

"Programming Erlang"

if/case

Erlang also has the usual if and case clauses:

1> if
     X > 1 ->
       "greater";
     X <= 1 ->
       " less or equal";
   end

There’s no explicit else, instead you just keep adding guards.

The case clause also looks pretty familiar:

1> Language = "Erlang".
2> case Language of
     "Erlang" -> "yay";
     "C#" -> "get out";
   end

The next chapter is about exception handling, then comes “advanced sequential programming” (sounds exciting, doesn’t it? :) )