Blog Categories
Ad Space
Twitter Updates
Powered by Squarespace
Git Projects
« Erlang Introduction (For the Ruby Guy) part 3 | Main | Installing Erlang and a few libraries on Mac OS X »
Sunday
10Aug

Erlang Introduction (For the Ruby Guy) part 2

Here is the second installment of the introduction to Erlang. In the first part I introduced you to some of the basics in the Erlang language and now it is time to get to know more of the fun parts of the language. Like the first part this is not supposed to be a tutorial. I am simplifying things here and there is a lot more you should know if you want to do an actual program in erlang. I highly recommend that you check out Kevin's Erlang in Practice screencast, Joe Armstrong's Programming Erlang book or the excellent documentation on the erlang website.

Funs

Funs are basically blocks. And much like you do in Ruby you will use funs a lot. A simple example of a fun would be:

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

Then you could make the call Double(10). and the result would be 20. Much like you do in Ruby you will often use Funs as parameters to functions. An example of a function that takes a fun is lists:map. This is a non object oriented version of Ruby's Array.map. It's first parameter is the fun to be run on each element and the next element is the list itself. Here we would make the call:

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

To create a new list with each element multiplied by 2. Another way to get the same result are by using list comprehensions.

List Comprehension

List Comprehensions are a great feature to create lists or manipulate lists. Lets start with the simple expression

[X*2 || X <- [1,2,3]].

This would create a new list with each element doubled. In english this would read "double each X where X is [1,2,3]". What is before || is called the expression and what comes after is referred to as the qualifiers. There can be multiple qualifiers like the example

[X || X <- [1,2,3,4], X > 2].

This would give out the result [3,4]. Here we the english term would be "display X where X is [1,2,3,4] and X is greater than 2".

A great example of how to use this can be read at WikiBooks. Here they give an example of using list comprehensions to solve an equation. The output of:

[ {X,Y} || X <- [1,2,3,4], Y <- [1,2,3,4], X*X == Y].

Would be [{1,1},{2,4}] and should be read "A tuple with the values X and Y where X is [1,2,3,4] and Y is [1,2,3,4] and where X time X equals Y". And how cool is that.

A type of list comprehension is also used in the powerful mnesia database system to query results instead of SQL. I highly recommend that you get to know it well.

Modules and Functions

The modules are really a collection of functions if you simplify things. There are differences of course since it's not objects you are working with. Lets just start with a simple module from the Erlang website. You can put this in a file called demo.erl and run the command erl in the same directory. You then compile the file typing c(demo). in the Eshell and run it by entering demo:double(2). to get the result 4.

-module(demo).
-export([double/1]).

double(X) ->
  times(X, 2).

times(X, N) ->
  X * N.

The first line is the name of the module. This must match the filename with the .erl extension excluded.

The second line is a list of what functions are exported. Only exported functions can be called from other modules. The list includes the function name and its arity. The arity states the number of parameters the function calls. If you want to export both functions the line would read -export([double/1,times/2]).. Note that you can have 2 functions with the same name but different arity and you would then have to export both versions.

Next up are the functions. This is pretty self explanatory. First up is the functions double that take one parameter and calls the second function times. Times takes 2 parameters and multiplies together.

One thing to notice is the dot (.) at the end. The dot says that this function is done. If this was a multi line function each line would end with a comma (,) except the last line that would end on either a dot or a semicolon (;) if the same function with the same arity is defined. Now this may sound a but confusing but lets look at how it works. The boss has asked me to change the double function that the whole company stands or falls with so that it would give me an error message if I decide to be a fool and double the number 0. If I were in ruby I might just add an if statement inside the function but this is erlang and things are done differently. Lets delete the whole double function and replace it with the following and recompile:

double(0) ->
  io:format("Only a fool would double a zero ~n"),
  0;
double(X) ->
  times(X, 2).

Here we see basically the same function twice. What happens here is really the same as the pattern matching in part 1. if we make he call demo:double(2). the erlang system first tries to match with double(0). Since 0 == 2 can not match it goes down do double(N). There it sees that it it can make true the statement X == 2 if X holds the value 2 and runs that function. Here we also see the the uses of commas and semicolons. First line in double(0) prints out a message to STDOUT and then the comma says that another statement is to follow. Then put out a single 0 because like in ruby the last statement is the return value of the function. This is followed by a semicolon to say that the function is over but that the same function will return but for a different value (It's actually not that simple but it's the simplest way to explain the behavior). Then at the end we have a period to say that all version of the function is over.

Another common way of usage is using tuples. Lets add convert/1 to our exports at the start of the file, add the following to the end of the file and recompile.

convert({cm, Value}) ->
  {inch, Value / 2.54};
convert({inch, Value}) ->
  {cm, Value * 2.54}.

Here we call convert/1 with a tuple. The first element in the tuple is the current unit of length and the second element is the value in that unit. It then returns a tuple with the new unit and the converted value. So the call demo:convert({inch, 1}). would give the result {cm, 2.54000}. Here we see in a great manner why we often have the first element in the tuple define what the whole tuple is like I mentioned in part 1.

Recursing Functions

One thing that, if you would do in ruby, would call for a lynching mob after you are recursive functions. In Erlang it's standard practice. Functions quite frequently call themselves. Lets look at an example of recursion by adding this to our demo.erl. Don't forget to export recurse/1.

recurse([]) ->
    io:format("All done.~n");
recurse([First|TheRest]) ->
    io:format("Value: ~p ~n", [First]),
    recurse(TheRest).

When we call this with an list like so: demo:recurse([1,2,3]).. it will first try to match with recurse([]) and be unable to do so since it's not an empty list. It will however match with the second function and create 2 variables. The variable First will hold the first value in the list and will be printed out but TheRest will hold the rest of the list. Then it calls itself again with the shortened TheRest list. In the end the list will be empty and match the first definition of recurse/1.

Conclusion

This should be good for now. Next article will go into processes mainly and give a little overview over the OTP principles.


Reader Comments (3)

Great series. Subscribed and looking forward to more.

I've gotten people using Ruby at work (in a previously pure Java shop). Now I'm trying to sell everyone on Erlang as well :D

August 11, 2008 | Unregistered CommenterJulian Doherty

Good explanation. I heard tuple in python but never know what is that(I am not a python guy) and not sure it has the same usage as Erlang. Well, at least learn new stuff now. Thanks and please continue the efforts :)

August 13, 2008 | Unregistered Commentersgwong

Good stuff.

A few details:

"Don't forget to export recursion/1" should be "Don't forget to export recurse/1"

"TheFist will hold the first value" should be "First will hold the first value"

August 19, 2008 | Unregistered CommenterUlf Wiger

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>