ONLamp.com
oreilly.comSafari Books Online.Conferences.

advertisement


An Introduction to Erlang
Pages: 1, 2, 3, 4

Elementary Erlang

Though we've looked at a couple trivial examples of Erlang code and played around with the shell a bit, we should really go over the core set of features you need to know about when working with any programming language. Erlang definitely does some things differently, so it's worth mentioning some of the surprises, too.



Erlang Variables Are Not-So-Variable

Once you bind a value to a variable in Erlang, it cannot be changed.

In practice, this is what that means:

  X = 3.

When you execute this code in Erlang, what actually happens is that the = operator compares the lefthand side to the righthand side and tries to find a pattern that matches them. It finds that the lefthand side is an unbound variable, and the righthand side is a value, so it then sets the variable's binding to that value.

You'll actually get an error message if you try something like this:

  X = 10.

You cannot change the state of a variable once it has been set. This prevents Erlang programs from relying on mutable state. Essentially, Erlang's notion of variables is closer to that of algebra than it is something like C or Java.

One limitation this imposes is that you can't do something like this in Erlang:

  X += 1

Most state transformations that are done in functional languages are done by creating new values, often building them up recursively, so this issue isn't as much of a concern as it might seem at first.

Further Down The Bunny Hole, The = Operator Doesn't Mean Assignment

In Erlang, assignment is just one of the many things that you do with =.

In fact, when you write something like X = 3., it is interpreted as a pattern, and the left and right sides are analyzed. On the lefthand side, we find an unbound variable, and the right side, a value. Erlang figures out that the smart thing to do is bind that variable to the value and that is when assignment actually happens. However, when you attempt to assign a new value to X, the pattern is different. In this case, the lefthand side is recognized as a bound variable, and will throw an error unless the value is exactly the same as the one the variable is bound to.

We'll revisit this topic when we look at some other structures, but it's worth keeping in the back of your mind that when you see = in Erlang, you shouldn't immediately assume that it means assignment.

Atoms and Tuples

Atoms in Erlang are somewhat similar to symbols in Ruby, and are simply named elements that you can use as labels in your code. You can use any lowercase alphanumeric characters, plus the @ and _ to construct an atom. The following are all examples of atoms.

1> A = foo.
foo
2> B = foo_bar.
foo_bar
3> C = foo@bar.
foo@bar

You can do equality comparisons on atoms:

4> A =:= foo.
true
5> B =:= foo.
false
6> C =:= foo.
false

However, they are mostly used in conjunction with Tuples, which are sets of arbitrary objects.

For example, we may have an address tuple, made up of other tuples and some atoms and text:

1> Address = { { name, "Gregory" }, { email, "gregory.t.brown at gmail.com" } }.

We could then extract out the information from the Tuple by giving a pattern that matches it:

2> { { name, Name }, { email, Email } } = Address.
{{name,"Gregory"},{email,"gregory.t.brown at gmail.com"}}
>> Name.
"Gregory" 
3> Email.
"gregory.t.brown at gmail.com"

In this example, the atoms are just used to help make it easier to know what the structure represents, and to make the patterns clearer. Though we won't cover them in this article, you'll want to have a look at Erlang's Records if you have a bunch of data with associative attributes.

Though you'll be sure to use plenty of atoms and tuples in your code, virtually all of your code will also make use of lists, so let's take a look at some of the common operations you can do with them.

Lists

Lists are collections of objects that have a head and a tail. The head of a list is the first element of the list in sequential order, and the tail is everything that's left over.

The following are all examples of lists:

1> L = [1,2,3,4].
2> L2 = ["kittens",trees,"bears",1,true].
3> L3 = [[{apple,banana},{cat,dog}],{tomato,avocado}].

We can separate the head from the tail of a list by using the | operator in a pattern:

4> [H1|T1] = L1.
5> H1.
1
6> T1.
[2,3,4]
7> L1.
[1,2,3,4]

Notice that the original list has not changed. We can use the same operator to efficiently construct a new list by appending a value to the head of an existing list:

8> L4 = [2|L2].
[2,"kittens",trees,"bears",1,true]
9> L2.         
["kittens",trees,"bears",1,true]

Again, notice that the original list is not modified, we are always creating new lists.

We can also do a large number of operations that act upon the whole list, but before we get into them, we should quickly cover Funs.

Anonymous Functions in Erlang

Funs are functions without a name that can be passed around as values. These should come as no surprise to anyone working in languages with lambdas, but might be a little tricky for those who haven't.

Here is a trivial example:

1> F = fun(X) -> X*X end.
#Fun<erl_eval.6.49591080>
2> F(10).
100
3> F(50).
2500

As you can see, we are basically creating a simple function that squares a value and assigning that function to a variable.

The real power here of course is that we can pass these anonymous functions around as if they were ordinary values, allowing us to even use them as arguments to functions.

Just to illustrate this, here is a trivial example. We will show some practical examples just around the bend when we cover list manipulations.

example.erl
call_with_five(Func) -> Func(5).

This function will call any function passed to it, passing it 5 as an argument. Playing around with the shell makes it clear how this works.

1> c(example).
{ok,example}
2> Fun1 = fun(X) -> X + 1 end.
#Fun<erl_eval.6.49591080>
3> Fun2 = fun(X) -> X * X end.
#Fun<erl_eval.6.49591080>
4> example:call_with_five(Fun1).
6
5> example:call_with_five(Fun2).
25

In a similar vein, you can also create anonymous function references to named functions:

6> example:call_with_five(fun example:fact/1).
120

You can actually do a lot more with Funs, but we'll stop here for now. It is worth noting that it is possible to create higher-order procedures by creating Funs which return Funs, but that's a bit out of the scope of this article.

For now, let's get back to list manipulations, where we'll use Funs to apply functions across all the elements of a list.

Pages: 1, 2, 3, 4

Next Pagearrow





Sponsored by: