aprendiendo ( Erlang ).

jueves, 7 de abril de 2011

Listas II. Listas por comprensión.

| 0 comentarios |

Las listas por comprensión, son expresiones que crean listas sin tener que usar funciones anónimas, maps, o filters. Esto hace que nuestros programas sean aún más cortos y fáciles de entender.
Las listas por comprensión consiste en una representación matemática de conjuntos. Por ejemplo, P={x ∈ N / x es menor de 5}, expresa el conjunto de los x tales que x es un número natural menor de 5.
1> [ X || X <- [1,2,3,4,6,7,5,9], X < 5 ].
[1,2,3,4]
El formato general de las listas por comprensión es: [X || generador1, filtro1, ...]. Donde X puede ser una expresión. En la expresión anterior, hemos utilizado un generador de X's y un filtro sobre dichos elementos pero puede haber más generadores y filtros. En algún, momento hemos utilizado la función map para calcular el doble de los elementos de una lista. ¿No queda más elegante, más limpio y legible de la siguiente forma?
2> [2*X || X <- lists:seq(1,5)]. 
[2,4,6,8,10] 
Os comente, en el post Listas, que la implementación que habíamos realizado de la función map no era la más eficiente. Pues bien, vamos a retomar el módulo de listas y realicemos la misma función con listas por comprensión ¿haber como nos queda?.
map(_, []) ->
    [];
map(F, [H|T]) ->
    [F(H) | map(F, T)].

map2(F, L) ->
    [F(X) || X <- L].
Es increíble lo claro y resumido que queda nuestra nueva definición de la función con respecto a la implementación anterior. Probemos la nueva implementación.
3> c(listas).
{ok,listas}
4> listas:map2 ( fun(X) -> X * 2 end, lists:seq(1,5)).
[2,4,6,8,10]
Ahora hagamos lo mismo con la función filter.
filter(_,[]) ->
    [];
filter(F,[H|T]) ->
    filter(F(H),F,H,T).

filter(true,F,H,T) ->
    [H | filter(F,T)];
filter(false,F,_,T) ->
    filter(F,T).

filter2(F, L) ->
    [X || X <- L, F(X)].
En este ejemplo se ve clara la diferencia entre las implementaciones y el comportamiento es el esperado.
5> c(listas).                                         
{ok,listas}
6> listas:filter2 ( fun(X) -> X rem 2 =:= 0 end, lists:seq(1,5)).
[2,4] 
Pero como es de esperar, las listas por comprensión no son la panacea. No se puede usar para todo, bueno, poderse, poderse... si que se puede pero se complica mucho y se pierde la simplicidad y legibilidad de las listas por comprensión. Por ejemplo, intenta cambiar la función sum y delete que implementamos anteriormente.
sum([H|T]) ->
    H + sum(T);
sum([]) ->
    0.

delete(_,[]) ->
    [];
delete(X,[X|T]) ->
    T;
delete(X,[H|T]) ->
    [H | delete(X,T)].
Complicado ¿verdad? Pero si podemos añadir una nueva funcionalidad a nuestro módulo de listas. Ahora vamos a implementa la función delete_all que borrará todas las incidencias de un elemento en una listas.
delete_all(X, L) ->
    [Y || Y <- L, Y /= X].
Otra implementación compacta y elegante.
7> c(listas).                                                    
{ok,listas}
8> listas:delete_all(2, [1,2,3,2,4,1,2]).
[1,3,4,1]
Continuara ...

Publicar un comentario

0 comentarios:

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