2009-04-21

Charla de erlang

El viernes pasado di una charla sobre erlang en el trabajo. En la misma, muestro como escribir programas secuenciales en erlang y después un poco de programación distribuida. Para presentar usé esta presentación (ojo, tenés que abrirla con OpenOffice). Abajo pongo lo que planifiqué dar (que es muy parecido a lo que di).

Programación secuencial

"Variables" inmutables

1> X = 1.
1
2> X = 2.
** exception error: no match of right hand side value 2
3> X = 1.
1

Atomos

4> aaaa.
aaaa
5> bbbb.
bbbb
6> Y = bbbb.
bbbb
7> Y.
bbbb
8> Y = aaaa.
** exception error: no match of right hand side value aaaa

Tuplas y listas (y pattern matching)

9> L = [1, 2, 3]
.
[1,2,3]
10> L2 = [-1, 0 | L]
.
[-1,0,1,2,3]
11> [H1, H2, H3 | _ ] = L2
.
[-1,0,1,2,3]
12> H1.
-1
13> H2.
0
14> H3.
1

15> Yo = {person, {fname, "Aureliano"}, {lname, "Calvo"}}.
{person,{fname,"Aureliano"},{lname,"Calvo"}}
16> Yo.
{person,{fname,"Aureliano"},{lname,"Calvo"}}
17> {person, {fname, Name},_} = Yo.
{person,{fname,"Aureliano"},{lname,"Calvo"}}
18> Name.
"Aureliano"

Expresiones case

34> X = 1. EL = []. L = [1,2,3].
1
35> []
36> [1,2,3]

38> case X of [] -> empty_list; [H|T] -> {head, H}; _ -> not_a_list end.
not_a_list
39> case EL of [] -> empty_list; [H|T] -> {head, H}; _ -> not_a_list end.
empty_list
40> case L of [] -> empty_list; [H|T] -> {head, H}; _ -> not_a_list end.
{head,1}

Funciones

En fruit.erl,

price( pear ) -> 4.0;
price( banana ) -> 3.0;
price( apple ) -> 6.0;
price( orange ) -> 2.0;

En consola,

13> fruit:price( pear ).
4.0
14> fruit:price( banana ).
3.0

Usando pattern matching un toque más en serio: En fruit.erl,

price( [] ) -> 0.0;
price( [{Kilos, Fruit}|Rest] ) -> Kilos * price( Fruit ) + price( Rest ).

En la consola,

15> fruit:price( [] ).
0.0
18> fruit:price( [{2.5, banana}, {1.5, apple}] ).
16.5

Pero para que use mejor el espacio (y no se acabe el stack), lo escribo tail recursive (acá explico que el stack sino se va a la mierda):

price2( L ) -> price2( L, 0.0 ).

price2( [], Acum ) -> Acum;
price2( [{Kilos, Fruit}|Rest], Acum ) -> price2( Rest, Kilos * price( Fruit ) + Acum ).

Programación distribuida

spawn, send y receive

spawn lanza un proceso nuevo de erlang, send (!) manda un mensaje a un proceso, y receive lo recibe.

Hago el fruit_shop.erl.

42> c( fruit_shop).
{ok,fruit_shop}
43> FS = fruit_shop:spawn_shop( [ {banana, 15.0}, {pear, 10.0}, {apple, 10.0}], [ {banana, 3.0}, {pear, 4.0}, {apple, 6.0} ] ).

Y lo uso:

(a@tango)3> fruit_shop:stock(FS).
[{banana,15.0},{pear,10.0},{apple,10.0}]
(a@tango)8> fruit_shop:buy(FS, [{2.0, apple}]).
{purchased,12.0}
(a@tango)10> fruit_shop:stock(FS).
[{apple,8.0},[{banana,15.0},{pear,10.0}]]

Por último, lanzar procesos en otros nodos es casi lo mismo: (spawn con un parámetro más, todo el resto igual).

Pongo 2 consolas de erlang:

>erl -sname a -setcookie oreo
>erl -sname b -setcookie oreo

En la primera lanzo la frutería sobre el segundo nodo:

(a@tango)7> FS = fruit_shop:spawn_shop( 'b@tango', [ {banana, 15.0}, {pear, 10.0
}, {apple, 10.0}], [ {banana, 3.0}, {pear, 4.0}, {apple, 6.0} ] ).

Hago lo mismo que antes:

(a@tango)3> fruit_shop:stock(FS).
[{banana,15.0},{pear,10.0},{apple,10.0}]
(a@tango)8> fruit_shop:buy(FS, [{2.0, apple}]).
{purchased,12.0}
(a@tango)10> fruit_shop:stock(FS).
[{apple,8.0},[{banana,15.0},{pear,10.0}]]

Mato la segunda consola y ahora las operaciones dan timeout:

(a@tango)11> fruit_shop:stock(FS).
timeout
(a@tango)12> fruit_shop:buy(FS, [{2.0, apple}]).
timeout

4 comentarios:

gerardocontijoch dijo...

Erlang.... que buenos recuerdos.

Una vez en un trabajo anterior no se bien porque motivo me pidieron que investigue Erlang. Fue una de las mejores cosas que hice en toda mi carrera como programador. Solo jugué 3 o 4 días con Erlang nada mas, pero eso me abrio la cabeza totalmente... yo acostumbrado a C#, VB, y demas lenguajes orientados a objetos.

Cada vez que escucho hablar de Erlang siempre me dan unas ganas de volver a jugar con el...

aurelianito dijo...

Lo que me gusta de Erlang es que es la primera vez que veo un lenguaje que me parece que tiene el enfoque apropiado para programar sistemas distribuidos.

Estoy completamente de acuerdo que te abre la cabeza a otras formas de pensar como programar ciertas cosas.

Una cosa más. Como está intimamente relacionado con el Modelo de actores (Actors Model), a mi me parece mucho más "orientado a objetos" que los lenguajes orientados a objetos que conozco. Un proceso de erlang es lo que yo me imagino que un objeto debería ser.

Anónimo dijo...

Conocés Axum?

Axum is a language that builds upon the architecture of the Web and principles of isolation, actors, and message-passing to increase application safety, responsiveness, scalability, and developer productivity.
Axum aims to validate a safe and productive parallel programming model for .NET.

Un proyecto en incubación en los labs de Microsoft... http://msdn.microsoft.com/en-us/devlabs/dd795202.aspx?1

aurelianito dijo...

Me lo mostró un compañero de laburo. Tiene toda la onda del modelo de actores también. Parece interesante, pero a mi me gusta más que los lenguajes tengan tipado dinámico (como erlang).

De todas maneras espero que lo sigan y lleguen a cosas interesantes, ya que programar separando procesos (actores o,como les dicen en Axum, agentes) al estilo erlang tiene su onda.