Erlang

De la Viquipèdia, l'enciclopèdia lliure
Aquesta és una versió anterior d'aquesta pàgina, de data 12:32, 4 abr 2016 amb l'última edició de Langtoolbot (discussió | contribucions). Pot tenir inexactituds o contingut no apropiat no present en la versió actual.
Aquest article tracta sobre el llenguatge de programació. Vegeu-ne altres significats a «Erlang (desambiguació)».

Erlang és un llenguatge de programació concurrent i base d'execució (en anglès runtime). 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 a ser usat en equips de comunicació, però va ser editat com a codi obert el 1998.

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)[1] i també per la coincidència amb "Ericsson language".

El compilador erlc per defecte genera codi intermedi amb extensió .beam perquè el runtime l'interpreti. Però hi ha d'altres formats i opcions.[2]

Existeix un compilador HiPE (High performace Erlang compiler)[3] desenvolupat per la Universitat d'Uppsala i actualment integrat en la distribució de codi obert. Per a utilitzarlo cal afegir el paràmetre [native] a l'ordre de compilació.[4]

Hi ha un compilador a codi Scheme anomenat EToS.[5]

Existeix també una distribució aprimada "Stand-alone Erlang"[6] que genera executables i no codi intermedi (requereix instal·lar des de l'usuari "joe").

El llenguatge seqüencial

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".

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]).

%% 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ó (en la cònsola werl (windows) o comanda erl (linux, 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 subsistema concurrent

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 a la comunicació entre ordinadors cal obrir el port 4369 del tallafocs per a TCP i UDP.[7][8]

  • la funció spawn(Mòdul, Funció, Args) crea un nou procés executant la funció especificada i retorna el PID (identificador) del procés creat.
  • la funció self() retorna el PID propi.
  • el símbol ! indica enviar. La construcció PID_destí ! {msg_id, Dades} envia dades al procés de destinació.
  • la construcció receive posa el procés en espera de recepció:
receive
    {msg_id1, Dades} -> <accions> ;
    {msg_id2, Dades2} -> <accions2> ;
    after Temporització_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 a 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 a 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).

Vegeu també

Referències

Enllaços externs

A Wikimedia Commons hi ha contingut multimèdia relatiu a: Erlang