UNIDAD IV

Programación Funcional

Profesor Miguel Cantillana

INS240 – Lenguajes de Programación
Ingeniería en Computación e Informática
Semestre 2017-1

Paradigma funcional con Python

Programación Funcional

¿Que significa funcional?

  • Es un paradigma de programación que está basado en funciones.
  • Se entiende el concepto de función según su definición matemática y no como simples subprogramas de los lenguajes imperativos.
  • Funciones puras
  • Las variables no tienen estado (Ausencia de estado): No hay cambios en éstas a lo largo del tiempo
  • Inmutabilidad: No pueden cambiarse los valores a lo largo de la ejecución.
  • Los programas se estructuran componiendo expresiones que se evalúan como funciones

Funciones puras e impuras

// Funcion Pura
 
function doble(num) {
  return num * 2; // No modifica el argumento.
}
 
function doblarLista(listado){
  // Retorna un nuevo listado sin modificar nada.
  return listado.map(doble); 
}
 
// Funcion Impura
 
function doblarLista(listado){
  for( var i =0; i < listado.items; i++ ){
    // Cambiamos los valores entregados como argumentos
    listado[i] = doble(listado[i]);
  }  
}

¿Por qué?

  • Facilitar el testing.
  • Reusabilidad.
  • Depuración más fácil.
  • Estado muy controlado.

¿Es python un lenguaje funcional?

  • No.
  • Es un lenguaje multi-paradigma.
  • Soporta algunas caracterı́sticas funcionales.
  • Permite hacer programación funcional.
  • Carece de caracterı́sticas avanzadas presentes en lenguajes funcionales.

¿Que me dan los lenguajes funcionales?

  • Estructuras inmutables eficientes.
  • Funciones de orden superior.
  • Pattern matching.
  • TCO: Tail call optimization.
  • Aplicación parcial y currificación.
  • Control de efectos laterales.
  • Funciones lambda.
  • Evaluación perezosa.
  • Composición de funciones.

¿Que nos entrega python?

  • Funciones de primer orden.
  • Funciones lambda.
  • Funciones de orden superior.
  • Evaluación perezosa (Limitada).

Tı́picas estrategias funcionales

  • Combinación y composición de funciones pequeñas.
  • Datos + funciones transformadoras.
  • Aplicación de transformaciones mediante orden superior.
  • Uso de funciones inline.
  • Acotado de efectos laterales.
  • Tendencia al uso de funciones puras.

Macrodiseño ⇒ Orientación a Objetos
Microdiseño ⇒ Programación Funcional

Funcional vs. Imperativo

Programación imperativa

  • Unidad sintáctica elemental: la sentencia
  • Operación elemental: la asignación
  • Modelo: variables ... “computar”
import random as r
x = 1
y = r . randint (0 ,10)
if y % 2:
    x = x + 3
else :
    x = x - 2
print x

Programación funcional

  • Unidad sintáctica elemental: la expresión
  • Operación elemental: la aplicación
  • Modelo: valores ... “calcular”
y = random . randint (0 , 10)
x = 1 + (3 if y % 2 else -2)
print x

Python Funcional

Funciones de primer orden o de orden superior

  • Genericidad: Las funciones pueden pasarse como parámetro.
  • Instanciación: Las funciones pueden devolver otras funciones.
  • Abstracción procedural: Cualquier sentencia puede convertirse en función.
  • Embebimiento: Las funciones pueden almacenerse en estructuras de datos.

Genericidad

  • Son funciones que reciben o devuelven funciones como parámetros.

  • Operan sobre funciones, es decir el dominio o la imagen de estas funciones son funciones.

Las funciones pueden pasarse como parámetro.

def ejecutarfun ( funcion ):
    res = funcion ()
    print " Resultado : " + str ( res )
ejecutarfun (random.random)

Genericidad (ii)

Las funciones pueden pasarse como parámetro.

def superior(interna):
    def funcion1():
        print "Funcion1"
    def funcion2():
        print "Funcion2"

    funcion = {
        'uno' : funcion1,
        'dos' : funcion2
    }
    return funcion[interna]

nueva_funcion = superior('dos')
nueva_funcion()

Genericidad (iii)

Las funciones pueden pasarse como parámetro.

def funcion1():
    print "Funcion1"

def funcion2():
    print "Funcion2"

def superior(funcion):
    funcion()

superior(funcion1)
superior(funcion2)

Instanciación

Las funciones pueden devolver otras funciones.

def devuelvefun ( param ):
    if param : return random.random
    else : return list

fun = devuelvefun ( True )
print fun ()
fun = devuelvefun ( False )
print fun ()

Abstracción procedural

Cualquier sentencia puede convertirse en función.


def make_sumador ( k ):
    def sumador ( x ):
        return x + k
    return sumador


mas_dos = make_sumador (2)
print mas_dos (1) # Imprime 3
print mas_dos (2) # Imprime 4

# Ejemplo (Abstracción + Instanciación)

Abstracción procedural ... Lambdas

lambda <parámetros>:<expresión></expresión></parámetros>

Son funciones anónimas, mínimas definidas en una línea, no pueden contener bucles y no pueden utilizar la palabra clave return para regresar un valor.

  • Lambda = Función anónima (sin nombre).
  • ¡Sólo expresiones!

Abstracción procedural ... Lambdas

cuadrado = lambda x: x ** 2
print cuadrado(2)

lista = range(10)

for numero in lista:
    print cuadrado(numero)

Abstracción procedural ... Lambdas

def make_sumador_lambda ( k ):
    return lambda x : x + k

mas_dos = make_sumador_lambda (2)
print mas_dos (1)
print mas_dos (2)

Embebimiento

Cualquier función puede guardarse en cualquier parte.

from operator import add , sub , div # , mul
funcs = { 
    '+' : add ,
    '-' : sub ,
    '*' : lambda a , b : a * b ,
    '/' : div 
}
print funcs ['+'] (1 , 2)
print funcs ['-'] (1 , 2)
print funcs ['*'] (1 , 2)
print funcs ['/'] (1 , 2)

Funciones de alto orden

Filosofı́a

Trabajar sobre listas ⇒ Abstraer la iteración

  • map (func, lista): Devuelve una lista aplicando func a cada elemento
  • reduce (func, lista, (primero)): Devuelve un valor aplicando la operación binaria func
  • filter (pred, lista): Devuelve una lista filtrando con el predicado pred

 

map (func, lista)

Aplica una función sobre cada ítem de una lista y devuelve una lista donde se le aplicó la función a cada elemento
nueva_lista = map(función, lista)

lista = [0,1,2,4,5,6,7,8,9]
lista_nueva = map(lambda x: x**2, lista)
print lista_nueva

reduce (func, lista, (primero))

reduce los ítems de una lista aplicando una función reductora, devuelve un solo valor
valor = reduce(función, lista, (primero))

lista = [0,1,2,4,5,6,7,8,9]
sumatoria = reduce(lambda x, y: x+y, lista)
print sumatoria

reduce (func, lista, (primero))

reduce los ítems de una lista aplicando una función reductora, devuelve un solo valor
valor = reduce(función, lista)

filter (pred, lista)

coteja que los elementos de una lista cumplan con cierta condición expresada en una función boolean.
nueva_lista = filter(funcion, lista)

lista = [0,1,2,4,5,6,7,8,9]
pares = filter(lambda x: x % 2 == 0, lista)
print pares

Otras utilidades

Emparejar los elementos de dos listas ...

zip ( 'hola' , range (3))

Verdadero si todos son verdaderos ...

all ([ True , [] , True ])

Verdadero si alguno es verdadero ...

any ([ True , [] , True ])

Listas por comprensión

Es una construcción compacta que permite mapear y/o filtrar una lista en otra aplicando una función a cada elemento de la lista, opcionalmente la lista original puede ser filtrada

Crear una lista con los cuadrados de los dígitos:

print [digito**2 for digito in range(10)] 

Crear una lista con los cuadrados de los digitos pares

print [digito**2 for digito in range(10) if digito % 2 == 0] 

Ejercicios en clases

Ejercicio 1

Escriba una función de orden superior que permita ejecutar una función n veces, donde n y la función debes ser argumentos.

 

Ejercicio 2

Implemente las funciones map, filter y reduce por sus propias manos.

Ejercicios en clases

Ejercicio 3

Sin utilizar bucles, implemente una función que reciba dos listas y devuelva otra lista con los productos de cada par de números.

 

Ejercicio 4

Realice el ejercicio anterior (Ejercicio 5), utilizando listas por comprensión. 

Recursos

  • http://librosweb.es/libro/algoritmos_python/capitulo_10/mutabilidad_e_inmutabilidad.html
  • https://www.genbetadev.com/paradigmas-de-programacion/programacion-funcional-un-enfoque-diferente-a-los-problemas-de-siempre
Made with Slides.com