Aquest article tracta sobre el llenguatge de programació. Vegeu-ne altres significats a «Erlang (desambiguació)». |
Tipus | llenguatge de programació multiparadigma, concurrent programming language (en) , llenguatge de programació funcional, llenguatge de programació declaratiu, llenguatge de programació, programari de codi obert, programari lliure i habilitat |
---|---|
Data de creació | 1986 |
Disseny | Joe Armstrong |
Desenvolupador | Joe Armstrong, Ericsson i Robert Virding |
Epònim | Agner Krarup Erlang i Ericsson |
Paradigma de programació | Programació declarativa, programació funcional, computació concurrent i programació multiparadigma |
Darrera versió estable | 27.2 () |
Llenguatge de programació | Erlang |
Influenciat per | ML, Prolog, Lisp, PLEX, Smalltalk, Miranda, Ada, Modula-2 i CHILL |
Sistema operatiu | multiplataforma |
Extensió dels fitxers | erl |
Codi font | Codi font |
Llicència | Llicència Apache, versió 2.0 i Erlang Public License (en) |
Pàgina web | erlang.org |
Erlang és un llenguatge de programació concurrent i un sistema d'execució (en anglès runtime) que inclou una màquina virtual (BEAM, acrònim de "Bogdan/Björn's Erlang Abstract Machine")[1] i biblioteques (OTP: "Open Telephony Platform").[2] El subsistema seqüencial és un llenguatge de programació funcional amb tipus dinàmics i avaluació estricta. El subsistema concurrent segueix el Model d'Actors.
Erlang era originalment un llenguatge de la casa Ericsson per ésser usat en equips de comunicació, però va ser editat com a codi obert el 1998.[3]
Ericsson va posar al llenguatge el nom d'Erlang com a tribut a Agner Krarup Erlang matemàtic danès pioner en l'estudi de xarxes de telecomunicacions (que també dona el seu nom a una mesura d'ús de la xarxa)[4] i també per la coincidència amb "Ericsson language".[5]
El compilador erlc per defecte genera codi intermedi amb extensió .beam perquè el runtime l'interpreti. Però hi ha d'altres formats i opcions.[6]
Existeix un compilador HiPE (High performace Erlang compiler)[7] desenvolupat per la Universitat d'Uppsala i actualment integrat en la distribució de codi obert. Per utilitzar-lo cal afegir el paràmetre [native] a l'ordre de compilació.[8]
Hi ha un compilador a codi Scheme anomenat EToS.[9]
Existeix també una distribució aprimada "Stand-alone Erlang"[10] que genera executables i no codi intermedi (requereix instal·lar des de l'usuari "joe").
El llenguatge utilitza una sintaxi similar a la del Prolog. S'estructura en una seqüència de clàusules cadascuna de les quals s'acaba en un . punt. Les clàusules no declaratives consten d'objectius alternatius (separats per ; punt i coma) basats en l'èxit de l'encaix de patrons (pattern matching). Cadascuna de les alternatives pot constar d'un seguit d'objectius en seqüència (separats per , comes).
Resumint i remarcant: A la fi d'una instrucció, la coma (operador de conjunció) indica seqüència, el punt i coma (operador de disjunció) introdueix alternativa (per ex. un altre cas d'encaix de patrons), i el punt indica final de clàusula (per ex. final d'una definició de funció).
Una funció s'identifica pel nom i el nombre de paràmetres (aritat) com ara "func/2". Dues funcions poden fer servir el mateix nom si tenen un nombre de paràmetres (aritat) diferent. S'acostuma a fer servir el mateix nom, per exemple quan cal definir una funció subordinada recursiva afegint un acumulador als paràmetres.
Les variables (assignables una sola vegada) comencen amb majúscula, les constants (dites àtoms) en minúscula o entre apòstrofs si contenen caràcters no alfanumèrics.
Les claus rectangulars [ ] indiquen llista, les arquejades { } indiquen tupla.
Els paràmetres formals no usats en una descripció de funció cal prefixar-los amb un caràcter de subratllat _ altrament mostra un missatge d'"Atenció variable no usada".
Avaluador d'expressions i documentació introductòria aquí.[11]
Exemple de programació (fitxer "fact.erl"):
-module(fact). % el mòdul ha de tenir el mateix nom que el fitxer
-export([fac/1, imprimeix_fac/1, llista_de_fac/1]). % llista de nom_funció/aritat
%% ';' (punt-i-coma) indica alternativa (disjunció d'objectius)
%% ',' (coma) indica seqüència (conjunció)
%% '.' (punt) indica fi de la clàusula o definició
%% factorial
fac(0) -> 1; % cas simple
fac(N) when N > 0 -> % cas recursiu
N * fac(N-1).
%% factorial amb recursivitat final
%% fac_rf/1 (1 paràmetre)
fac_rf(N) ->
fac_rf(N, 1).
%% fac_rf/2 (2 paràmetres)
fac_rf(0, Acum) -> Acum ;
fac_rf(N, Acum) when N > 0 ->
fac_rf(N-1, N * Acum).
imprimeix_fac(N) ->
R = fac_rf(N),
io:format("El factorial de ~w és ~w~n", [N, R]).
llista_de_fac([]) -> true; % cas simple
llista_de_fac([ Cap_de_llista| Resta]) -> % cas recursiu
imprimeix_fac(Cap_de_llista),
llista_de_fac(Resta).
Compilació i execució a l'avaluador d'expressions (cònsola werl (cas de windows) o comanda erl (unix, windows)):
>c(fact). % compila fact.erl generant codi intermedi a fact.beam
{ok. fact}
>fact:imprimeix_fac(4) % crida mòdul:funció(paràmetres)
El factorial de 4 és 24
ok
>fact:llista_de_fac([2,3,4]).
El factorial de 2 és 2
El factorial de 3 és 6
El factorial de 4 és 24
true
El llenguatge incorpora un sistema de creació de processos en el propi runtime independent del propi del sistema operatiu, així com un sistema de comunicació entre ells.
Per la comunicació entre ordinadors cal obrir el port 4369 del tallafocs per a TCP i UDP.[12][13]
receive
{msg_id1, Dades} -> <accions> ;
{msg_id2, Dades2} -> <accions2> ;
after Termini_en_milisegons -> <accions_cas_de_no_rebre_res>
end.
Un node és una instància del runtime de Erlang en un ordinador (host) determinat. La comunicació es pot establir entre diversos nodes del mateix o de diferents sistemes via TCP/IP.
Un exemple:
-module(tut19).
-export([start_ping/1, start_pong/0, ping/2, pong/0]).
%% ping -- cas simple (N = 0)
ping(0, _Pong_Node) ->
io:format("ping ha acabat ~n", []);
%% ping -- cas recursiu
ping(N, Pong_Node) ->
{pong_pid, Pong_Node} ! {msg_ping, self()}, % envia un msg_ping a pong amb el pid propi (''self()'')
receive
msg_pong ->
io:format("Ping ha rebut pong ~n", [])
end,
ping(N - 1, Pong_Node). % recursivitat final (descomptant una vegada)
pong() ->
receive
{msg_ping, Ping_PID} ->
io:format("Pong ha rebut ping ~n", []),
Ping_PID ! msg_pong, % li torna un msg_pong
pong() % torna a esperar (recursivitat final)
after 20000 ->
io:format("Pong s'ha cansat d'esperar i plega ~n", [])
end.
start_pong() ->
register(pong_pid, spawn(tut19, pong, [])). % registra l'àtom pong_pid amb valor de l'id. del procés engegat (spawn)
start_ping(Pong_Node) ->
spawn(tut19, ping, [3, Pong_Node]).
Per provar-ho en una mateixa màquina o en dues màq. de la mateixa xarxa local engegarem dues finestres de comandes des del directori del fitxer "tut19.erl". En una escriurem la comanda
>erl -sname pong
Eshell V5.5.4
(pong@host_a)1>c(tut19). % compila
{ok, tut19}
(pong@host_a)2>tut19:start_pong().
(pong@host_a)3>
En l'altra
>erl -sname ping
Eshell V5.5.4
(ping@host_b)1>tut19:start_ping(pong@host_a).
(ping@host_b)2>
i ja en veureu el resultat. Per provar-ho en dues màquines de xarxes diferents cal fer servir l'opció -name en comptes de -sname i posar-hi el nom qualificat del host (nom d'internet, com ara host.domini.tld).