Erlang Introduction

by "Blag" - Senior Developer Evangelist

Return to Geeky Thursday

What is Erlang?


Erlang is a general-purpose concurrent, garbage-collected programming language and runtime system.

It's also a functional language, with eager evaluation, single assignment and dynamic typing.


Designed by Ericsson - hence the name "Ericsson Language".

Now it's Open Source.


Makes you throw away all your previous programming dogmas.

How to install Erlang?


Erlang can be downloaded from here Erlang

Windows and Mac version comes as a Binary File. Windows comes with a really nice shell.

Linux version can be installed from source or using apt-get.

erlide is an Eclipse based IDE.

For Linux or Windows we can (and we're going to use) Geany.

If you're on Mac follow this Geany OSX.

Who uses Erlang?


  • Amazon -> SimpleDB, providing database services as part or EC2
  • Yahoo! -> Delicious, which has more than 5 million users and 150 million bookmarked URLs
  • Facebook -> Backend of its chat service, with more than 100 million active users
  • WhatsApp -> Messaging services, achieving 2 million connected users per server
  • T-Mobile -> SMS and authentication systems
  • Ericsson -> Support nodes, used in GPRS and 3G networks worldwide
  • CouchDB -> "Schema-less" document oriented database

Starting out...


To begin with...we're going to call Erlang from the terminal.


Variables


Variables are not variable...


Once assigned...variables cannot change...they're immutable...

				
MyVariable = "This is my variable".

"This is my variable"



MyVariable = "This could be your variable".

** exception error: no match of right hand side 

   value "This could be your variable"
				

Every command must end with a period "."


Variables must start with an Uppercase letter.


Starting with a Lowercase letter creates an "atom".


Atoms are not variables, but string representations...like Constants.


Erlang has dynamic typing...what you assign to a value, it becomes its type...

				
thisisanatom.

thisisanatom


thisisanatom = "My Atom".

** exception error: no match of right hand side 
  
   value "My Atom"



IntegerValue = 1977.

1977
				

Variables can't change their values after assignment...


So how can we update their values?


We can't...we need to use a new variable...


				
X = 10.

10



X = 10 + 5.

** exception error: no match of right hand 
 
   side value 15
   
   
   
Y = X + 5.

15
				

Tuples

Sometimes, we need to group values together...


For that, we can use Tuples...


				
Person = {blag,37}.

{blag,37}



{Name,Age} = Person.

{blag,37}



Name.

blag
				

We can create nested tuples...

				
AnotherPerson = {wolverine,210}.

{wolverine,210}



People = {Person,AnotherPerson}.

{{blag,37},{wolverine,210}}
				

Lists

We can use Lists to handle Tuples in a better way...

				
People = [{blag,37},{wolverine,210},{bart,11}].

[{blag,37},{wolverine,210},{bart,11}]



[Head|Tail] = People.

[{blag,37},{wolverine,210},{bart,11}]



Head.

{blag,37}



Tail.

[{wolverine,210},{bart,11}]
				

Strings

Strings are not strings...They're a list of integers...

				
"Hello World".

"Hello World"



[72,101,108,108,111,32,87,111,114,108,100].

"Hello World"



$H.

72



[87].

"W"
				

Our first application


For this application we need to create a file called "greetings.erl" (with all lowercase)...


				
-module(greetings).

-export([greet/2]).



greet(male, Name) ->

    io:format("Good morning Mr. ~s~n", [Name]);
    
greet(female, Name) ->

    io:format("Good morning Mrs. ~s~n", [Name]);
    
greet(_, Name) ->

    io:format("Good morning ???. ~s~n", [Name]).
				

Before we can call our App, we need to compile it...


On Geany, just click the "Compile the current file" button.


Then you will need to click the "Run or view the current file" button.


If you're not using Geany then from the command line call...


erlc "name_of_file" to compile


erl and the "filename:functionname(parameters) to run it...


When we run it we're going to see...


Functions

Function are very important...In Erlang everything is a function.


There's no such things as Classes or Objects.


We can define the same function name with different number of parameters.


They will be treated as completely different functions.


Recursion is very important...we'll see that later...


Our second application

This example will call the same function with different number of parameters...


You can call it "numbers.erl" (with all lowercase)


				
-module(numbers).

-export([num/1,num/2]).



num(Number) ->

    io:format("This is your number ~p~n",[Number]).
    
num(Number1,Number2) ->

    io:format("This is the sum of two numbers ~p~n",
    
              [Number1 + Number2]).    
				

When we run it we're going to see...


Recursion

Recursion is one of the key points in Erlang...you call a function that calls itself multiple times.


As we can't change the value of a variable, we can pass different values as parameters.


This way we can update the variable value without changing the variable value...


Also, we can use something called "Pattern Matching" which is used to determine which function to call...

Our third application

This example will create a Fibonacci Number Generator.


You can call it "fibonacci.erl" (with all lowercase)


				
-module(fibonacci).

-export([fib/1]).




fib(Number) ->

    fib(Number,0,1,"").
    
fib(1,_,_,Acc) ->

    io:format("~p~n",["0 1 " ++ Acc]);
    
fib(Number,A,B,Acc) when A > 0 ->

    fib(Number - 1, A + B, A, Acc ++ 
    
        integer_to_list(A + B) ++ " ");            
        
fib(Number,A,B,Acc) ->

    fib(Number - 1, A + B, B, Acc ++
    
        integer_to_list(A + B) ++ " ").            
				

When we run it we're going to see...


Making an LED Number App


Name your file "led_Numbers.erl"


				
-module(led_Numbers).

-export([showLED/1]).
				
				
showLED(Number) when is_integer(Number) ->

	Digits = [ X - 48 || 
	
	           X <- integer_to_list(Number) ],

    Leds = #{0 => {" _  ","| | ","|_| "}, 
		
             1 => {"  ","| ","| "},

             2 => {" _  "," _| ","|_  "},

             3 => {"_  ","_| ","_| "},

             4 => {"    ","|_| ","  | "},

             5 => {" _  ","|_  "," _| "},

             6 => {" _  ","|_  ","|_| "},

             7 => {"_   "," |  "," |  "},

             8 => {" _  ","|_| ","|_| "},

             9 => {" _  ","|_| "," _| "}},


	build_output(Digits,Digits,Leds,1,"").
				
				
build_output([],_,_,3,Acc) -> 

	io:format("~s~n",[Acc]);


build_output([],Digits,Leds,LineNo,Acc) -> 

    build_output(Digits,Digits,Leds,
    
                 LineNo+1,Acc++"\n");


build_output([H|T],Digits,Leds,LineNo,Acc) -> 

	build_output(T, Digits,Leds,LineNo,
	
	             Acc++element(LineNo,
	             
	             maps:get(H,Leds))).
				

When we run it we're going to see...


Random Names


This App will generate 100,000 random names using two 16 elements arrays


We will measure the runtime


Name your file "random_names.erl"


				
-module(random_names).

-export([show_names/0, run_names/0]).


   
show_names() ->

	Names = ["Anne","Gigi","Blag","Juergen",
	
	         "Marek","Ingo","Lars","Julia",
	         
	         "Danielle","Rocky","Julien",
	         
                 "Uwe","Myles","Mike","Steven",
             
                 "Fanny"],
				
				
	Last_Names = ["Hardy","Read","Tejada",
	
	              "Schmerder","Kowalkiewicz",
	              
	              "Sauerzapf","Karg","Satsuta",
	              
	              "Keene","Ongkowidjojo",
	              
	              "Vayssiere","Kylau","Fenlon",

                      "Flynn","Taylor","Tan"],

    generate_names(Names,Last_Names). 
			
				
generate_names(Names,Last_Names) ->

	_ = [ lists:nth(rand:uniform(16),Names) 
	
	      ++ " " ++ 
	
	      lists:nth(rand:uniform(16),Last_Names)
	      
	      ++ "\n" || _ <-lists:seq(1,100000) ],
	      
	io:format("Done").
	
	
run_names() ->

    {Time, _} = timer:tc(random_names,show_names,[]),

    RunTime = Time /1000000,

    io:format("\n~p~n",[RunTime]).	
			

When we run it we're going to see...


Less than a minute...that's impressive...

Decimal to Romans


This App will create a Roman Numeral based on a decimal number


This will include some nice commands...


Name your file "dectoroman.erl"


				
-module(dectoroman).

-export([showRomans/1]).



showRomans(Number) when is_integer(Number) ->

	Roman_Nums = [{1000,"M"},{900,"CM"},{500,"D"},
	
                      {400,"CD"},{100,"C"},{90,"XC"},
                  
                      {50,"L"},{40,"XL"},{10,"X"},
                  
                      {9,"IX"},{5,"V"},{4,"IV"},
                      
                      {1,"I"}],

	showRomans(Number,Roman_Nums,1,"").
			
				
showRomans(0,_,_,Acc) ->
 
	io:format("~s~n",[Acc]);

showRomans(Number,Roman_Nums,Counter,Acc) ->

	case Number >= 
	
	element(1,lists:nth(Counter,Roman_Nums)) of

	true -> showRomans(Number - 
		
	element(1,lists:nth(Counter,Roman_Nums)),
	
	Roman_Nums,Counter,Acc ++ 
		        
	element(2,lists:nth(Counter,Roman_Nums)));

	false -> showRomans(Number,Roman_Nums,
	
	Counter + 1,Acc)

	end.  
			

When we run it we're going to see...


Concurrency


Create processes in Erlang is both easy and inexpensive.

We can create a dozen, hundrer or even thousand of processes...and they act independentely.

Name your file "concurrent.erl"


				
-module(concurrent).

-export([run/1]).




proc1(N) when N < 1000 ->

	proc1(N+1);

proc1(N) -> 

	io:format("Process 1: ~p~n",[N]),

	io:format("Sleeping~n"),

	timer:sleep(3000).                                           
			
				
proc2(N) when N < 1000 ->

	proc2(N+1);

proc2(N) -> 

	io:format("Process 2: ~p~n",[N]).



run(N) ->

	proc1(N),
	
	proc2(N),
	
	proc1(N),
	
	proc2(N),
	
	spawn(fun() -> proc1(N) end),
	
	spawn(fun() -> proc2(N) end).
			

When we run it we're going to see...


Mnesia


Mnesia is Erlang's own DBMS...


It's bundled inside Erlang, so there's no need for third party components.


Also it's distributable over nodes.


It uses transactions making rollbacks, backups and restores a pretty easy task.



We're going to build an app to store Music Albums...


You can call it "mnesiadex.erl" (with all lowercase)



				
-module(mnesiadex).



-include_lib("stdlib/include/qlc.hrl").



-export([initialize/0,start/0,stop/0,add_album/3,

         remove_album/1,show_albums/0,show_artist/1]).



-record(music, {id, artist, album}).					
				
				
initialize() ->

	mnesia:create_schema([node()]),

        mnesia:start(),

        mnesia:create_table(music, 
        
        [{attributes,record_info(fields, music)},
        
         {disc_only_copies,[node()]}]),mnesia:stop().


    
start() ->

    mnesia:start(),

    mnesia:wait_for_tables([music], 20000).


    
stop() ->

    mnesia:stop().
				
				
do(Q) ->

    F = fun() -> qlc:e(Q) end,

    {atomic, Val} = mnesia:transaction(F), Val.


    
add_album(Id, Artist, Album) ->

    Row = #music{id=Id, artist=Artist, album=Album},

    F = fun() ->

        mnesia:write(Row)

    end,

    mnesia:transaction(F).
				
				
remove_album(Id) ->

    Oid = {music, Id},
    
    F = fun() ->
    
        mnesia:delete(Oid)
        
    end,
    
    mnesia:transaction(F).



show_albums() ->

    do(qlc:q([{X#music.album,X#music.artist} || 
    
               X <- mnesia:table(music)])).

    
show_artist(Artist) ->

    do(qlc:q([X#music.album || 
    
              X <- mnesia:table(music),
              
                   X#music.artist =:= Artist])).
				

When we run it we're going to see...


That's all for now...


I hope you had some fun...


I hope you liked Erlang


I hope you will give Functional Programming a second look -;)


Contact Information


Blag --> blag@blagarts.com

@Blag on Twitter

Go back home...