aprendiendo ( Erlang ).

lunes, 28 de marzo de 2011

Funciones de alto nivel. Fun's.

| 1 comentarios |

Las funs son funciones anónimas, funciones lambda's en otros lenguajes. Estas fun's pueden ser asignadas a variables, veamos un ejemplo de lo que digo:
1> Doble = fun (X) -> X*2 end.
#Fun
2> Doble(4).
8
3> Otro_doble = Doble.
#Fun
4> Otro_doble(4).
8 
Como podemos observar en el ejemplo hemos creado una variable Doble que referencia a una función anónima con aridad 1 y la podemos utilizar o invocarla utilizando dicha variable.
Una fun puede tener varias clausulas como cualquier otra función.
5> Suma_doble = fun (X, Y) -> Z = X + Y,
5> Z * 2
5> end.
#Fun
6> Suma_doble ( 1, 3 ).
8 
El interprete de la consola de Erlang extiende el comando 5 ya que sabe de antemano que no se a concluido con la expresión.
Erlang es un lenguaje funcional y como tal, nos permite hacer un uso intensivo de las funciones anónimas. Ya hemos visto como podemos crearlas, y como invocarlas, pero también, nos permite pasarlas como argumentos de otras funciones y funciones que retornen otras funciones. Este tipo de funciones son lo que se denominan funciones de alto nivel.

Funciones como argumentos

Un ejemplo típico e implementado en todo lenguaje funcional que se precie es la función map, que aplica una función a todos los elementos de una lista. En Erlang, la función map pertenece al módulo lists y, recibe como argumentos una función y una lista.
7> lists:map(Doble, [1,2,3,4]).
[2,4,6,8]
8> lists:map(Suma_doble, [1,2,3,4]).  
** exception error: interpreted function with arity 2 called with one argument
     in function  lists:map/2
En la línea 7, hemos utilizado la función map con la fun Doble y una lista, y nos retorna otra lista que, a cada elemento de la lista original se le ha aplicado la función anónima.
Aunque he dicho que map recibe una función no es del todo cierto. No nos vale cualquier función, en la línea 8 he intentado utilizar la otra fun que teníamos creada, Suma_doble, y hemos obtenido un error. Esto es debido a que el perfil de la función que espera map es con aridad 1 y la función pasada tiene aridad 2.
Ahora, como es de rigor, vamos a complicar la cosa. Vamos a implementar la fun en formato inline.
9> lists:map(fun(X) -> X * 2 end, [1,2,3,4]).               
[2,4,6,8]
En este caso, en la misma línea, hemos realizado lo mismo pero ahorrándonos el uso de una definición de variables y, parece más claro. La verdad es que..., si la fun es sencilla y no la vamos a reutilizar en futuras llamadas es interesante pero en otros caso es conveniente implementarla inline.
Otra función del estilo y que debe estar en todo lenguaje funcional, es un filtro filter y en este caso, vamos a filtrar los pares de una lista de enteros.
10> lists:filter(fun(X) -> X rem 2 =:= 0 end, [1,2,3,4]).
[2,4]
Ahora, el perfil de la fun a pasar al filtro no sólo tiene que tener aridad 1, sino que tiene que ser una función booleana, lógico no?

Funciones que retornan Fun's

Otra característica del paradigma funcional es la posibilidad de tener funciones que generen otras funciones. Y para variar, vamos poner un ejemplo.
11> Test = fun(L) -> fun(X) -> lists:member(X,L) end end.    
#Fun
12> EsColor = Test([azul,verde,rojo]).   
#Fun
13> EsFruta = Test([pera,manzana,platano]).
#Fun
14> EsColor(rojo).
true
15> EsColor(manzana).
false
16> EsFruta(manzana).
true
17> EsFruta(verde).  
false
En la línea 11, tenemos una función que nos permite crear una función de test más o menos genérica. A partir de la función Test, podemos crear otras funciones de test como EsColor, que recibe un color y comprueba si se trata de un color, EsFruta que hace lo propio para frutas.
Suponte que te dijera, que generalizaras nuestra función Doble, es decir, crear una función para Triple o para cualquier otra cantidad. Pues nada hacemos algo así ...
18> Veces= fun(N) -> ( fun(X) -> X * N end ) end.
#Fun
19> Triple = Veces(3).
#Fun
20> Triple(2).
6
21> Triple(3).
9
En definitiva, las funciones anónimas y las funciones de alto nivel son una herramienta muy, muy potente. Si os pasa como a mí, empezaras con unos simples ejemplos, luego lo usas un poco más en profundidad y finalmente consigues hacer verdaderas genialidades. Espero que como a mí, os entusiasmen las funciones anónimas y de alto nivel ...

Publicar un comentario

1 comentarios:

  1. Anónimo dijo...

    Buenas! Aquí no sería offline en lugar de inline?
    "...si la fun es sencilla y no la vamos a reutilizar en futuras llamadas es interesante pero en otros caso es conveniente implementarla inline.".

 
Licencia Creative Commons
Aprendiendo Erlang por Verdi se encuentra bajo una Licencia Creative Commons Atribución-NoComercial-CompartirIgual 3.0 Unported.