Cursos‎ > ‎Cursadas Anteriores‎ > ‎2010‎ > ‎Jueves Mañana‎ > ‎Funcional‎ > ‎

Clase 4



Listas por comprensión

  • Comparamos las listas por comprensión con el uso de filter y map y vemos que la función
    nombresDeAlumnosQueAprobaron = map nombre . filter aprobo

    puede también escribirse como una lista por comprensión:
    nombresDeAlumnosQueAprobaron alumnos = [nombre alumno | alumno <- alumnos, aprobo alumno]

  • Una diferencia que podemos notar entre ambas definiciones es la cantidad de parámetros a la izquierda del igual, en el segundo caso hay uno, mientras que en el primero no hay. ¿Por qué pasa eso?

    Eso pasa porque
    map nombre . filter aprobo
    es una función ya que es la composición de dos funciones.

    En cambio
    [nombre alumno | alumno <- alumnos, aprobo alumno]
    es una lista, esa es una diferencia importante y es un criterio que nos va a permitir saber cuándo nos conviene usar map y filter en lugar de listas por comprensión.

  • Otra cosa que agregan las listas por comprensión es la posibilidad de hacer pattern matching:
    [nombre | (nombre, nota) <- alumnos, nota > 4]

  • Otro ejemplo si tengo una lista de remeras de la forma:
    modelos = [("GoodIdeaBadIdea", "flex", 2, "negro"), ...]

    a partir de esa lista podemos construir otra usando listas por comprensión y pattern matching:
    [(nombre, color) | (nombre, _, cant, color) <- modelos, cant > 2]

    Aquí se puede ver la verdadera potencia de las listas por comprensión vs. map y filter, la posibilidad de utilizar el pattern matching.

  • En resumen:
    • Las listas por comprensión nos dan funcionalidades similares a las del map y filter, entonces es probable que en muchas situaciones se presenten como soluciones alternativas a un mismo problema.
    • Las listas por comprensión permiten aprovechar mejor el pattern matching, entonces en los casos donde pueda usar esa característica probablemente sea más piola usar listas por comprensión en lugar de map y filter.
    • Con listas por comprensión yo siempre defino una lista, mientras que combinando map y filter con aplicación parcial yo puedo definir funciones, eso los hace más aptos para la composición, por lo tanto en los casos en que yo necesite componer (o trabajar al nivel de función por cualquier otro motivo, puede resultar más adecuado usar map, filter, aplicación parcial, composición, etc.

Definiciones Locales

  • Si tengo una función muy particular que sólo voy a utilizar en un contexto particular, podemos definir la función localmente, usando la forma where.
  • Ejemplo:
    f = map nombreYColor . filter ((>2).cantColores)
         where nombreYColor remera = (nombre remera, color remera)

Expresiones lambda

  • Una forma alternativa a lo anterior es evitar incluso ponerle nombre, podemos evitar la parte izquierda de la definición.
  • Esta herramienta la denominamos expresión lambda, y se puede usar de la siguiente manera:
    f = map nombreYColor . filter (\remera -> cantColores remera > 2)

  • O incluso:
    f = map (\remera -> nombre remera, color remera) . filter (\remera -> cantColores remera > 2)

    Este segundo caso es más poderoso, ya que esa función no se puede definir utilzando aplicación parcial y composición.

Ejercitación

A partir de esta información:

modelos = [("GoodIdeaBadIdea", "flex", 2, "negro"), ...]
pedido = [("Mariana", [("GoodIdeabadIdea", "S"), ("Animaniacs", "S")], ("Nico", [("Solong", "M"), ...])]
precio (_, "flex", cant, _) = 50 + cant
precio (_, _, _, _) = 60

nombreModelo (modelo, material, cantidadDisponible, color) = modelo
colorModelo (modelo, material, cantidadDisponible, color) = color

nombreRemeraPedida (nombre, cantidad) = nombre


Vamos a tratar de resolver los siguientes requerimientos:
  • Buscar una remera por su nombre entre una lista de modelos
    remeraLlamada nombre = find ((==nombre).nombreModelo)

  • Obtener una lista con tuplas cuyo primer elemento es el nombre de un comprador compulsivo (compró más de tres remeras) y el segundo una lista de los colores posibles para las remeras que compró.
    coloresParaCompradoresCompulsivos ps =
    [(nombre, coloresPara remeras) | (nombre, remeras) <- ps, length remeras > 3]
       where coloresPara = map (colorModelo . remeraLlamada . nombreRemeraPedida)

  • Calcular cuánto debe pagar una persona:

  • Dada una lista de pedidos obtener los nombres de las personas que obtuvieron una remera xl o xxl
Comments