Erlang (programspråk)

Erlang är ett generellt programspråk som från början (år 1987) utvecklades på forskningsavdelningen  hos telebolaget Ericsson AB vid utvärderingen av olika programspråk för implementation av styrsystemen i telefonväxlar. Språket är ett funktionellt programspråk, utan typdeklarationer och med dynamisk typning. Eftersom språket är designat för parallell bearbetning på flera sammankopplade system är det också synnerligen väl lämpat för användning på moderna flerkärniga datorer. Erlangs namn är avsiktligt fyndigt taget både efter (den i telefonsystem förekommande) enheten Erlang och som sammansättningen av Ericsson Language. Året 1998 släpptes språket fritt som öppen källkod och används nu av flera internationella företag. Enligt Joe Armstrong, skaparen av Erlang, var språket ett rent forskningsprojekt från 1986 till 1997 då det som följd av projektet AXE-N:s kollaps valdes som bas för en ny ATM-växel med namnet AXD 301, vars programsystem var helt baserat på Erlang.

Kodexempel

Hello world
Ett exempel som returnerar atomen hello_world. Alla program måste ha ett modul-namn och exportera funktioner för att de ska kunna anropas externt.

 -module(hello).
 -export([world/0]).
 
 world() -> hello_world.

Fakultetfunktion

Fakultet är ett typiskt problem som man löser rekursivt. Men rekursion är traditionellt sett — speciellt i språk som C — minneskrävande, då man behöver allokera minne för varje gång man kallar på en funktion. Så är det även i Erlang och liknande språk, men med ett undantag: Erlang anstränger sig för att, när den kan, frigöra minnet associerat med en funktion. Därför är det av yttersta vikt att använda sig av tekniken "svansrekursion" (eng: tail recursion), och alltså inte utföra något alls efter att man kallat på sig själv. Följande kodexempel kan vid första glimt se ut att följa just denna princip, men det är först när fac returnerar multiplikationen sker.

 -module(test).
 -export([fac/1]).
 
 fac(0) -> 1;
 fac(N) -> N * fac(N-1).

I Erlang löser man det genom att skicka med ackumulatorer som argument. En korrekt lösning på fakultetsproblemet skulle alltså kunna se ut så här:

 -module(test).
 -export([fac/1]).
 
 fac(N) -> fac(N, 1).
 fac(0, A) -> A;
 fac(N, A) -> fac(N-1, A*N).

Här illustreras även att en funktion med olika antal parametrar i själva verket inte är samma funktion. Den andra raden exporterar bara den funktion som heter fac och tar ett — och endast ett — argument.

Interprocesskommunikation
Grundläggande i semantiken för Erlang är processer, som är isolerade från varandra. Det enda sättet för processer att kommunicera är genom att skicka meddelanden mellan sig.

Nedan följer ett exempel över en modul med två publika funktioner:
 create_server - Funktion för att skapa en process som lyssnar på meddelanden.
 greet - Funktion för att skicka ett meddelande till processen.

 -module(messages).
 -export([create_server/0, greet/2]).
 
 create_server() -> spawn_link(fun() -> server_proc() end).
 
 % Serverproceduren som tar emot meddelanden.
 server_proc() ->
     receive 
         {meddelande,A} -> io:fwrite("Meddelande: "++A)
     end,
     server_proc(). 
 
 % Server = process-ID för servern.
 % Medd = meddelandet.
 greet(Server,Medd) ->
     Server ! {meddelande, Medd}.

Funktionen create_server returnerar en processidentitet (PId), vilken används av greet-funktionen för att veta till vilken process meddelandet skall skickas.

 PId = messages:create_server().
 messages:greet(PId, "Hello world!").

Det går även att namnge processer med register(RegName, Pid)-funktionen.

 PId = messages:create_server().
 register(my_server, PId).
 messages:greet(my_server, "Hello world!").

Case-satser
Varje case-sats (sv. falluppdelning) börjar med "case" följt av ett uttryck följt av "of" och sedan flera olika fall och avslutas med "end". Varje sats evalueras genom att P evalueras och sedan går man igenom de olika fallen (varje fall följs av en pil ->). Så fort uttrycket satisfieras fallet köra man uttrycket som följer efter ->, och de resterande fallen hoppar man över. Till exempel om vi låter P = 2 då kommer vi satisfiera det första fallet och då returnera 2 * 2 = 4. -module(case).
 -export([conditional/1]).
 conditional(P) ->
     % För att visa, anta att P inte bör skyddas av funktionsklausulen
     case P of
         P when is_integer(P) ->
             2*P;
         P when is_list(P) ->
             hd(P);
         _ ->
             fel
     end.

Mönstermatchning
 % Sker vid 
 % 1. Funktionsanrop, 
 % 2. case/receieve/try 
 % 3. (=)-operatorn
 -module(matchning).
 -export([funktion/1,
         konditionell/1,
         tilldelning/0]).
 funktion([]) ->
     [];
 funktion([First | _Tail]) ->    
     First.
 konditionell(X) ->    
     case X of
         A when is_atom(A) ->            
             A;
         B when is_integer(B) ->
             B;
         _ ->
             fel
     end.
 tilldelning() ->
     % A binds till 1
     % B binds till [2,3]
     [A | B] = [1,2,3],
     % C binds till 2, D till 3
     [C, D] = B,
     A + C + D.

List-konstruktion
Genom att deklarativt beskriva elementen i en lista byggs den sedan induktivt.
 -module(listcomp).
 -export([squarePositives/1]).
 squarePositives(List) ->
     [A*A || A <- List, A > 0].I detta fallet skulle sista raden utläsas som: för varje element i listan List som är strikt större än noll låt elementet bli dess kvadrat i en ny lista.

Externa länkar
Öppen källkodsimplementation
Erlang gemenskap
Svensk sida

Referenser

Funktionella programspråk
Ericsson
Programspråk
Programspråk som stödjer samtidighet
Dynamisk typade programspråk