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

2009-04-10

como sacar numeros del 0 al 9 con los digitos 4 4 4 4 (parte 3)

Sigo jugando con los 4s y ahora quería contarles una curiosidad. Si saco la potenciación de las operaciones posibles, se pueden armar los mismos números que antes:

0 == (4 / (4 * (4 * 4)))
1 == (4 / (4 / (4 / 4)))
2 == (4 / ((4 + 4) / 4))
3 == ((4 + (4 + 4)) / 4)
4 == (4 - (4 / (4 * 4)))
5 == ((4 + (4 * 4)) / 4)
6 == (4 + ((4 + 4) / 4))
7 == (4 + (4 - (4 / 4)))
8 == (4 - (4 - (4 + 4)))
9 == (4 + (4 + (4 / 4)))
10 ==
11 ==
12 == (4 * (4 - (4 / 4)))
13 ==
14 ==
15 == ((4 * 4) - (4 / 4))
16 == (4 * (4 / (4 / 4)))
17 == ((4 / 4) + (4 * 4))
18 ==
19 ==
20 == (4 * (4 + (4 / 4)))
21 ==
22 ==
23 ==
24 == (4 + (4 + (4 * 4)))
25 ==
26 ==
27 ==
28 == ((4 * (4 + 4)) - 4)
29 ==
30 ==
31 ==
32 == ((4 * 4) + (4 * 4))
33 ==
34 ==
35 ==
36 == (4 + (4 * (4 + 4)))
37 ==
38 ==
39 ==
40 ==
41 ==
42 ==
43 ==
44 ==
45 ==
46 ==
47 ==
48 == (4 * (4 + (4 + 4)))
49 ==
50 ==


¿Loco no? Para probarlo, saquen ** de la lista de posibles operadores y corran el script de la entrada anterior del blog.

Happy hacking,
Aureliano.

como sacar numeros del 0 al 9 con los digitos 4 4 4 4 (parte 2)

En la entrada anterior del blog puse el desafío de calcular los números del 1 al 50 haciendo operaciones aritméticas sobre 4 4s, y como generarlos para los números que van del 0 al 9. Pero me quedé con la duda de si es posible hacerlo para todos los números menores a 50, así que escribí un programita en ruby que calcula todas las posibles evaluaciones usando los operadores +, -, *, / y **. Lo único, hay que tener en cuenta que la división es entera, por lo que hay algunos resultados poco intuitivos.

Al final, el primer número imposible es el 10 (por eso no encontraba como armarlo :D). Acá les muestro la salida del programa:

0 == (4 / (4 ** (4 ** 4)))
1 == (4 ** (4 / (4 ** 4)))
2 == (4 / ((4 + 4) / 4))
3 == (4 - (4 ** (4 - 4)))
4 == (4 ** (4 ** (4 - 4)))
5 == (4 + (4 ** (4 - 4)))
6 == (4 + ((4 + 4) / 4))
7 == (4 + (4 - (4 / 4)))
8 == (4 - (4 - (4 + 4)))
9 == (4 + (4 + (4 / 4)))
10 ==
11 ==
12 == (4 * (4 - (4 / 4)))
13 ==
14 ==
15 == ((4 * 4) - (4 / 4))
16 == (4 * (4 ** (4 / 4)))
17 == ((4 / 4) + (4 * 4))
18 ==
19 ==
20 == (4 * (4 + (4 / 4)))
21 ==
22 ==
23 ==
24 == (4 + (4 + (4 * 4)))
25 ==
26 ==
27 ==
28 == ((4 * (4 + 4)) - 4)
29 ==
30 ==
31 ==
32 == ((4 ** 4) / (4 + 4))
33 ==
34 ==
35 ==
36 == (4 + (4 * (4 + 4)))
37 ==
38 ==
39 ==
40 ==
41 ==
42 ==
43 ==
44 ==
45 ==
46 ==
47 ==
48 == (4 * (4 + (4 + 4)))
49 ==
50 ==

Y para los geeks codeadores como yo, este fue el script rubyistico que usé para calcular las cosas:
def template_expressions( leafs = 4 )
  return "4" if leafs == 1
  previous_level = template_expressions( leafs - 1 )
  previous_level.map do
    |expr|
    results = []
    (0...expr.length).each do
      |i|
      if expr[i..i] == "4"
        new_result = expr.clone
        new_result[i] = "(4 o 4)"
        results << new_result
      end
    end
    results
  end.flatten
end

OPERANDS = %W{+ - * / **}

def sample_evaluations( leafs = 4 )
  evaluations = {}
  exprs = template_expressions(leafs)
  exprs.each do
    |expr|
    sample_evaluations0( leafs, expr, evaluations )
  end
  evaluations
end

def sample_evaluations0( leafs, expr, evaluations )
  if leafs == 0
    begin
      evaluations[eval( expr )] = expr
    rescue ZeroDivisionError
    end
    return
  end
  
  OPERANDS.each do
    |op|
    new_expr = expr.sub( /o/, op)
    sample_evaluations0( leafs - 1, new_expr, evaluations )
  end
end

evaluations = sample_evaluations
(0..50).each { |i| puts "#{i} == #{evaluations[i]}" }


Happy hacking,
Aureliano.

como sacar numeros del 0 al 9 con los digitos 4 4 4 4

Hoy estaba mirando la página del Google Analytics del blog y encontré una busqueda muy rara que entró por acá: "como sacar numeros del 1 al 50 con los digitos 4 4 4 4". Estuve pensando un poco que quería decir e inventé que tenía que hacer operaciones aritméticas comunes sobre los 4 4s y obtener los números del 1 al 50.
Me salieron los números del 1 al 9 (y le agregué el cero de yapa). Los anoté en notación "ruby" para que puedan hacer cut&paste en el irb.
0: 4+4-4-4
1: (4+4)/(4+4)
2: (4/4) + (4/4)
3: (4+4+4)/4
4: (4**(4-4))*4
5: (4**(4-4))+4
6: ((4+4) / 4) + 4
7: (4+4) - (4/4)
8: 4+4+4-4
9: (4+4) + (4/4)

Ahora me queda la duda de si se pueden, o no, armar todos los números del 1 al 50 de esta manera. Quizás debería escribir un programita que prueba todas las opciones.

Happy hacking,
Aureliano.