Comunidad de diseño web y desarrollo en internet online

Funciones Anonimas: que son y para que sirven ruby, javascript python

Citar            
MensajeEscrito el 05 Mar 2012 09:07 pm
Hola a todos, hoy vamos a ver qué son las funciones anónimas, tan populares en los lenguajes funcionales pero que también han sido incorporadas a lenguajes como javascript, ruby (llamadas bloques o lambdas) y python (lambdas).

Aunque respeto mucho el lenguaje python, los lambdas de python son bastante limitados ya que aceptan una sola línea de código, en ruby las funciones sólo pueden recibir un bloque (hasta donde se :oops: ) y en javascript probablemente es donde están mas desarrollados, a la par de los lenguajes funcionales (si te interesa node.js y sus callbacks necesitas entender las funciones anónimas), es por eso que voy a usar javascript como lenguaje de ejemplo, pero es muy sencillo llevar el codigo a ruby o python...

Pero qué demonios son las funciones anónimas y para qué alguien querría escribir una función anónima? (sin nombre). La respuesta es sencilla, úsalos cuando te interese pasarle una función a otra función; suena algo abstracto pero es muy simple, imagina la función como un pedazo de código, existen momentos en la vida en la que tienes un código muy complejo con partes que se repiten y partes que no, usando lambdas puedes escribir una función para la parte que se repite y luego que esa función reciba como argumento los pedazos de código que no se repiten; complicado?...veamos un ejemplo:

Supongamos que tenemos un array y que iterar a través de ese array 100 veces aplicando diversas operaciones a sus valores, en unos casos queremos multiplicar * 2 sus valores, en otras sumarles 5, etc...

El código para 2 de esos 100 casos sería así:

Código Javascript :

var array = [1,2,3,4];      //este es el array con el que trabajaremos (nombre bastante original)   

var arrayPor2 = [];
for ( i = 0; i< array.length; i++ ){
    arrayPor2.push(array[i]*2);
};

var arraymas5 = [];
for ( i = 0; i< array.length; i++ ){
    arraymas5.push(array[i]+5);
};

console.log(arrayPor2);
console.log(arraymas5);



Si tienes firefox puedes probar el código usando firebug, aunque recomiendo usar nodejs y así escribir el código en tu editor de texto favorito y correr node para ver el resultado.

Dos detalles: primero el encapsulamiento es bastante feo en este ejemplo, estoy creando variables como arraypor2 o arraymas5 que las arrastro durante todo el código, lo segundo es que si nos fijamos, lo único que cambié en los dos ejemplos es la línea donde sumo 5 o multiplico por 2. En este ejemplo es muy sencillo pero en códigos mas complejos, no sería recomendable repetir el mismo código varias veces así que vamos a escribir una función que encapsule el código que se mantiene igual y que reciba como argumento el código que cambia (a través de una función) además que encapsulando queda todo más decente y legible, por lo que matamos 2 pájaros de un tiro...

La función que va a encapsular lo que se repite, es parecida al método each de ruby, así que si usas ruby y nunca has escrito un código como el de arriba (y te has librado de java o c#) ahora vas a entender que hace el each (y la gran librería de enumerables de ruby)

Código Javascript :


function each (objeto, funcionAAplicar){
    var mem = [];
    for ( i = 0; i< objeto.length; i++ ){
        mem.push(funcionAAplicar(objeto[i]));
    };
    return mem;
};


var arrayPor9 = each(array, function(x){return x*9})
console.log(arrayPor9);
console.log(  each( [2,4,5454,43344]  , function(x){return x*12} )  );



Ok no se asusten, se que la función each parece fea en un principio pero la verdad es muy sencilla: esta recibe 2 argumentos, que son el objeto al que le voy a aplicar la función y la función anónima. Esta función es más parecida al each que van a conseguir en underscore.js que al each de ruby, porque en ruby el objeto no es un argumento, sino que es quien llama a la función (al ser ruby 100% orientado a objetos permite esto de manera clara).

Código :

array.each{|x| x*9}


En javascript es posible pero no quiero complicar el ejemplo, en fin, como vimos recibe el objeto y una función que no tiene nombre que se encarga de entregarle el pedazo de código que cambia, cuando itero llamo a esa función y le paso como argumento cada uno de los valores del array. Con esto ganamos dos cosas: escribimos un each genérico que sirve para cualquier código (puedes usarlo para multiplicar, dividir, etc. cada uno de los valores del array sin tener que escribir un for loop nunca más :D )

Vamos a complicar el ejemplo un poco más y vamos a crear un filter que filtre los valores que cumplen una condición, como esa condición siempre cambia, o puede ser que no la sabemos al momento de escribir nuestro código (si escribes un código para que otro programador lo use tienes que tratar de ser genérico y ser más flexible: otra ventaja de las funciones anónimas)...dejemos la cháchara y piquemos código:

Código Javascript :

function filter (objeto,funcionAAplicar){
    var mem = [];
    for ( i = 0; i< objeto.length; i++ ){
        if (funcionAAplicar(objeto[i])){
            mem.push(objeto[i]);
        }
    };
    return mem;
};

var mayoresq100 = filter([1,2,3,4,121,323], function(x){return x>100})

console.log(mayoresq100);


Aquí simplemente colocamos un condicional que prueba si la función anónima entrega true o false y de ahí decidimos qué valores metemos al array, veámoslo mejor:

function(x){return x>100}
Si le paso un 10 como argumento a esta función me entrega false, si le paso 200 es true.
Cuando itero con el for, le voy pasando cada uno de los valores a esa función y veo si me devuelve un false o un true, de ahí decido cuales meter en el array mem, si quisiera escribir un except que hiciera lo contrario, metiendo los valores menores a 100, simplemente cambiaría el if...algo como

Código Javascript :

if (!funcionAAplicar(objeto[i])){



Simple pero efectivo. Así como hice con estos dos ejemplos pueden hacer con casi todos los métodos de enumerable de ruby, o la biblioteca underscore.js http://documentcloud.github.com/underscore/#each

Si quieren practicar allí tienen ejemplos para horas de "distracción y esparcimiento" :D :D ;D


Otra ventaja de las funciones anónimas es que nos permiten controlar recursos, aquí no voy a dar muchos detalles porque la idea es simple, hay veces donde por cuestiones de recursos o seguridad, para hacer una operación necesitas abrir y cerrar el recurso una vez terminada la misma. Por ejemplo, al escribir el disco, o en un fichero, normalmente necesitamos usar un open y un close (que pasa si por mala suerte se te olvida cerrar el recurso??) tu computadora explota y mueres en el intento de escribir un fichero :D ...un ejemplo genérico sería:

Escrito en lenguaje PurPleScript
manejadorDarchivos = new ManejadorDArchivosComeRecursos() //siempre se repite
manejadorDarchivos.abrirArchivo("c://fotosDGatitos/")
insertarArchivo("domokuComeGatito.jpg")
manejadorDarchivos.close() //siempre se repite

Fíjense que aquí solo 2 líneas son importantes para nosotros, pero las otras dos son tan importantes que siempre las tenemos que incluir...

esto sería sencillo de escribir usando funciones anónimas, simplemente tendrías que escribir la parte que siempre se repite dentro de una función y la parte que cambia sería una función anónima, que es llamada dentro de la función principal:

en javascript para llamar una función anónima se hace así:

Código Javascript :

( function saludar(){console.log("hola como estas")} )();  // con esto invocamos la funcion anonima recien creada


Sabiendo esto deberías poder escribir el ejemplo que puse de abrir y cerrar archivos (eso si el fabuloso lenguaje PurPleScript tiene funciones anónimas como javascript)

SI has usado processing (un magnifico lenguaje basado en java usado para crear obras visuales, ejemplos en openprocessing.com) habrás visto alguna vez que para dibujar usando líneas tienes que escribir algo como:

Código Java :


beginShape();
vertex(20, 20);
vertex(45, 20);
vertex(45, 80);
endShape(CLOSE);


Si se nos olvida cerrar la figura nuestro código se va al trasto!!

Eso porque nuestros queridos amigos de processing al usar java no tienen funciones anónimas (el nuevo jvm creo que si tendrá lambdas), vamos a escribir una función que nada mas reciba los vértices y que se encargue de abrir y cerrar la figura.

Sería algo así:

Código Javascript :

function shape(verticesfunc){
  beginShape();
  (verticesfunc)();
  endShape(CLOSE);
}

shape(function(){ 
  vertex(20, 20);
  vertex(45, 20);
  vertex(45, 80);})




Si usas node o estás interesado aprenderlo, los callbacks son prácticamente funciones anónimas anidadas, una función anónima dentro de otra, dentro de otra, dentro de otra, dentro de otra, tal vez mas adelante escriba algo sobre ello.

Si usas c# visual basic o familia no te preocupes, el clr agrega funciones anónimas desde hace tiempo, aunque originalmente usaban una alternativa (fea, verborreica y complicada) llamada delegados que se encargaba de lo mismo, de esto si tengo pendiente un tutorial pues a pesar que el clr agrega los lambdas para usar muchas bibliotecas de .net aun se necesitan los delegados, igual que para manejar eventos....

Cualquier error por favor corríjanlo, además no se copien de mi artículo y si comparten el enlace tírenme un crédito, el articulo pienso publicarlo en ingles en un blog que voy a hacer (algún día, lo escribiré encima de mi vaca voladora). Comentarios, sugerencias, hablen con el administrador...

Por DrOctopus

0 de clabLevel



 

firefox
Citar            
MensajeEscrito el 06 Mar 2012 03:38 am
hola DrOctopus. Estoy corrigiendo tu tutorial. Podrías ponerle algunos subtítulos? lo redactas todo muy de corrido, como si estuvieras charlando, y debe estar mas estructurado el tuto para que se entienda mejor. Haces demasiados comentarios que quitan al lector de lo que estás explicando.

Podrías reverlo y acomodarle unos títulos y subtitulos? podes repostear acá mismo o abre un nuevo post .

y porfa. usa el corrector ortográfico...

saludos

Por Mariux

BOFH

7756 de clabLevel

28 tutoriales
15 articulos

Genero:Femenino   Héroes Editores

Diseñadora & ilustradora

chrome
Citar            
MensajeEscrito el 16 Abr 2012 01:50 pm
movido a aportes

Por Mariux

BOFH

7756 de clabLevel

28 tutoriales
15 articulos

Genero:Femenino   Héroes Editores

Diseñadora & ilustradora

chrome

 

Cristalab BabyBlue v4 + V4 © 2011 Cristalab
Powered by ClabEngines v4, HTML5, love and ponies.