← Scala EspañolChapter 10 of 13

Programacion Funcional

## Objetivos de Aprendizaje - Comprender principios de programacion funcional - Dominar funciones de orden superior - Aprender closures - Trabajar con currying - Comprender aplicacion parcial ## Principios de Programacion Funcional ### Funciones Puras Una funcion pura: - Devuelve el mismo resultado para las mismas entradas - No tiene efectos secundarios (sin E/S, sin mutacion) ```scala // Funcion pura def add(a: Int, b: Int): Int = a + b // Funcion impura (tiene efecto secundario) var counter = 0 def nextInt(): Int = { counter += 1 counter } ``` ### Inmutabilidad Prefiere estructuras de datos inmutables: ```scala // Enfoque inmutable val original = List(1, 2, 3) val added = 0 :: original // Nueva lista: List(0, 1, 2, 3) // Enfoque mutable (evitar cuando sea posible) import scala.collection.mutable val buffer = mutable.ListBuffer(1, 2, 3) buffer.prepend(0) // Muta buffer ``` ## Funciones de Orden Superior Funciones que toman funciones como parametros o devuelven funciones: ```scala def applyTwice(f: Int => Int, x: Int): Int = f(f(x)) def double(x: Int): Int = x * 2 def increment(x: Int): Int = x + 1 applyTwice(double, 3) // 12 (3 * 2 * 2) applyTwice(increment, 3) // 5 (3 + 1 + 1) ``` ### Funciones de Orden Superior Comunes ```scala val numbers = List(1, 2, 3, 4, 5) // map - transforma cada elemento numbers.map(_ * 2) // List(2, 4, 6, 8, 10) // filter - mantiene elementos que satisfacen el predicado numbers.filter(_ % 2 == 0) // List(2, 4) // flatMap - map y luego flatten numbers.flatMap(x => List(x, -x)) // List(1, -1, 2, -2, 3, -3, 4, -4, 5, -5) // fold/reduce - combina elementos numbers.fold(0)(_ + _) // 15 (suma) numbers.reduce(_ * _) // 120 (producto) // collect - emparejamiento de patrones y transformacion numbers.collect { case x if x % 2 == 0 => x * 2 } // List(4, 8) ``` ## Closures Un closure captura variables de su entorno: ```scala def multiplier(factor: Int): Int => Int = { (x: Int) => x * factor // factor es capturado } val triple = multiplier(3) triple(5) // 15 val double = multiplier(2) double(5) // 10 ``` ### Captura Mutable ```scala var factor = 1 val incrementAndMultiply: Int => Int = (x: Int) => { factor += 1 x * factor } incrementAndMultiply(5) // 6 (factor se convierte en 2) incrementAndMultiply(5) // 15 (factor se convierte en 3) ``` ## Currying Convertir una funcion con multiples parametros en una cadena de funciones: ```scala def add(a: Int)(b: Int): Int = a + b add(3)(5) // 8 val addFive = add(5) _ addFive(3) // 8 addFive(10) // 15 ``` ### Beneficios del Currying ```scala // Sin currying def withLogging(f: () => Unit): () => Unit = { () => { println("Before") f() println("After") } } // Con currying def withLogging(f: => Unit): Unit = { println("Before") f println("After") } def greet(): Unit = println("Hello!") withLogging(greet) ``` ## Aplicacion Parcial Proporcionar algunos argumentos, dejando otros para despues: ```scala def multiply(a: Int, b: Int, c: Int): Int = a * b * c val multiplyBy2 = multiply(2, _, 3) // Parcialmente aplicada multiplyBy2(5) // 30 (2 * 5 * 3) val multiplyBy6 = multiply(2, 3, _) // Parcialmente aplicada multiplyBy6(5) // 30 (2 * 3 * 5) ``` ## Composicion de Funciones ### Compose ```scala val double = (x: Int) => x * 2 val addOne = (x: Int) => x + 1 val doubleAddOne = double compose addOne // (x + 1) * 2 doubleAddOne(5) // 12 ``` ### AndThen ```scala val double = (x: Int) => x * 2 val addOne = (x: Int) => x + 1 val doubleThenAddOne = double andThen addOne // (x * 2) + 1 doubleThenAddOne(5) // 11 ``` ### Usando con expresiones for ```scala case class Person(name: String, age: Int, city: String) val people = List( Person("Alice", 30, "NYC"), Person("Bob", 25, "LA"), Person("Charlie", 35, "NYC") ) val nycNames = for { p <- people if p.city == "NYC" } yield p.name // List("Alice", "Charlie") ``` ## Estructuras de Datos Funcionales Puras ### Listas Persistentes ```scala sealed trait List[+A] case object Nil extends List[Nothing] case class Cons[A](head: A, tail: List[A]) extends List[A] object List { def apply[A](as: A*): List[A] = if (as.isEmpty) Nil else Cons(as.head, apply(as.tail: _*)) def foldRight[A, B](as: List[A], z: B)(f: (A, B) => B): B = as match { case Nil => z case Cons(x, xs) => f(x, foldRight(xs, z)(f)) } } ``` ## Evaluacion Perezosa ### Evaluacion Perezosa con `lazy` ```scala lazy val expensive = { println("Computing...") 42 } println("Before") println(expensive) // Computing... luego 42 println(expensive) // Solo 42 ``` ### Listas Perezosas (Streams) ```scala import scala.collection.immutable.LazyList def fibonacci: LazyList[Int] = { def go(a: Int, b: Int): LazyList[Int] = a #:: go(b, a + b) go(0, 1) } fibonacci.take(10).toList // List(0, 1, 1, 2, 3, 5, 8, 13, 21, 34) ``` ## Tipos de Funciones | Tipo | Descripcion | |------|-------------| | `Int => Int` | Funcion de Int a Int | | `(Int, Int) => Int` | Funcion con dos parametros Int | | `() => Unit` | Funcion sin parametros | | `Int => Boolean` | Predicado sobre Int | | `(Int, Int) => Boolean` | Predicado binario | ## Metodos vs Funciones ```scala class Calculator { def add(a: Int, b: Int): Int = a + b } val calc = new Calculator() // Metodo - eta expansion convierte a funcion val addFunction: (Int, Int) => Int = calc.add _ // Funcion directa val add = (a: Int, b: Int) => a + b ``` ## Optimizacion de Recursion de Cola ```scala def factorial(n: Int): BigInt = { @annotation.tailrec def loop(acc: BigInt, n: Int): BigInt = { if (n <= 1) acc else loop(acc * n, n - 1) } loop(1, n) } ``` ## Resumen - La programacion funcional enfatiza funciones puras e inmutabilidad - Las funciones de orden superior toman o devuelven funciones - Los closures capturan variables del entorno - El currying divide funciones de multiples parametros en cadenas - La aplicacion parcial fixa algunos argumentos para despues - La composicion de funciones crea nuevas funciones a partir de existentes - La evaluacion perezosa difiere el calculo hasta que sea necesario - La recursion de cola se optimiza para evitar desbordamiento de pila - Preferir val sobre var, inmutable sobre mutable

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →