Funciones

Programación funcional y reactiva - Computación

Profesor: Ing. Santiago Quiñones

Docente Investigador

Departamento de Ingeniería Civil

Contenidos

Func. matemáticas hacia la programación funcional

Funciones matemáticas

Algo para recordar

Definición: Relación que asigna a cada elemento de entrada exactamente un elemento de salida

Propiedades: 

  • Determinista: La misma entrada siempre produce la misma salida
  • Sin efectos secundarios
  • Notación: f(x) = y

Funciones matemáticas

Propiedades

Determinismo: 

  • Para cada entrada, hay exactamente una salida
  • f(x) produce siempre el mismo resultado para el mismo x
  • No hay aleatoriedad ni dependencia del contexto

Transferencia referencial: 

  • Una función puede ser remplazada por su valor sin cambiar el comportamiento del programa
  • Si f(3) = 5, podemos reemplazar f(3) por 5 en cualquier lugar

Sin efectos colaterales: 

  • Evaluar una función no modifica nada fuera de ella
  • No cambia variables globales
  • No modifica sus argumentos
  • No realiza operaciones de I/O

Del mundo matemático al mundo computacional

La pregunta clave: ¿Podemos programar de la misma manera que definimos funciones matemáticas?

La respuesta: Sí, y ese es el paradigma funcional.

Funciones matemáticas

Funciones matemáticas

Transformación de función matemática a código

def f(x: Int) = Math.pow(x, 2) + 1
f(x) = x^2 + 1

Funciones puras

Funciones puras

Definición

Una función pura es una función que:

  1. Para los mismos argumentos siempre retorna el mismo valor
  2. No produce efectos colaterales (side effects)

Es la traducción directa de una función matemática al código.

Funciones puras

Ejemplos

Es pura porque:

  • suma (3,  4) siempre será 7
  • no modifica nada externo
def suma(a: Int, b: Int): Int = a + b

Ejemplo 1

Es pura porque:

  • Para la misma lista, siempre da el mismo resultado
  • No modifica la lista original
  • No usa ni modifica variables externas
def promedio(numeros: List[Int]): Double = {
  val suma = numeros.sum
  val cantidad = numeros.length
  suma.toDouble / cantidad
}

Ejemplo 2

Funciones no puras

Ejemplos

No es pura porque:

  • incrementarContador(5) puede dar resultados diferentes según el valor de contador
  • Modifica una variable externa
var contador = 0

def incrementarContador(x: Int): Int = {
  contador = contador + x  // ❌ Modifica estado externo
  contador
}

Ejemplo 1: Depende de estado externo

Funciones no puras

Ejemplos

No es pura porque:

  • El contenido del archivo puede cambiar
  • Puede fallar (archivo no existe)
  • Depende del sistema de archivos
def leerArchivo(nombre: String): String = {
  scala.io.Source.fromFile(nombre).mkString  // ❌ I/O
}

Ejemplo 2: Operaciones de I/O

Funciones puras

Antitesis

Funciones puras

Principales características

Funciones puras

Implementación en Scala

object Counter {
  // Función pura que incrementa un contador
  def incrementCounter(counter: Int): Int = {
    counter + 1
  }

  // Función pura que multiplica el contador
  def multiplyCounter(counter: Int, num: Int): Int = {
    counter * num
  }

  // Función pura que devuelve el valor del contador (en este caso innecesario porque el
  // no necesita una función, simplemente se usa directamente)
  def getCounter(counter: Int): Int = {
    counter
  }
}

// Uso de las funciones
val currentCounter = 5
val incremented = Counter.incrementCounter(currentCounter)
val multiplied = Counter.multiplyCounter(currentCounter, 2)

println(s"Incremented: $incremented")  // Imprimirá 6
println(s"Multiplied: $multiplied")    // Imprimirá 10

Funciones vs Métodos

Trabajo en grupo

¿Cuándo es mejor usar funciones puras y cuándo métodos de objetos?

Debate de cada enfoque

Funciones puras vs Métodos (Leng. Prog.)

Diferencias conceptuales

  • Una función no tiene "estado". Su única misión es transformar los valores de entrada en una salida. No existen efectos secundarios.
  • En los lenguajes de programación, un método podría modificar el estado interno de un objeto o tener efectos como imprimir en la consola o alterar el contenido de una variable externa.

Método en POO

Ejemplo

class Contador {
  private var valor: Int = 0  // Estado mutable
  
  def incrementar(): Unit = {  // Método
    valor += 1  // Modifica estado interno
  }
  
  def obtenerValor(): Int = valor
}

val c = new Contador()
c.incrementar()  // Primera llamada
c.obtenerValor()  // Devuelve 1
c.incrementar()  // Segunda llamada
c.obtenerValor()  // Devuelve 2 - ¡Resultado diferente!

Funciones en programación funcional

Ejemplo

// No hay clase con estado
def incrementar(valor: Int): Int = valor + 1

val valor1 = 0
val valor2 = incrementar(valor1)  // 1
val valor3 = incrementar(valor2)  // 2

// Cada llamada es independiente
incrementar(5)  // Siempre devuelve 6
incrementar(5)  // Siempre devuelve 6

Comparación directa

Lenguaje Scala

Tipos básicos

// Numéricos
val entero: Int = 42
val largo: Long = 42L
val flotante: Float = 3.14f
val doble: Double = 3.14159

// Booleano
val verdadero: Boolean = true
val falso: Boolean = false

// Caracter y String
val letra: Char = 'A'
val texto: String = "Hola mundo"

// Unit (equivalente a void)
val nada: Unit = ()

Funciones

Definición básica

// Sintaxis completa
def nombreFuncion(parametro1: Tipo1, parametro2: Tipo2): TipoRetorno = {
  // cuerpo de la función
  resultado
}

// Ejemplo
def suma(a: Int, b: Int): Int = {
  a + b
}

// Si el cuerpo es una sola expresión, se pueden omitir las llaves
def suma2(a: Int, b: Int): Int = a + b

// Scala infiere el tipo de retorno (pero es buena práctica especificarlo)
def suma3(a: Int, b: Int) = a + b

Funciones

Funciones anónimas (lambdas)

// Sintaxis completa
val sumar = (a: Int, b: Int) => a + b

// Uso
sumar(3, 4)  // 7

// Con un solo parámetro
val cuadrado = (x: Int) => x * x
cuadrado(5)  // 25

// Sintaxis abreviada con placeholder
val doble: Int => Int = _ * 2
doble(5)  // 10

Otra forma de definir funciones

Los métodos también pueden tener expresiones de varias líneas.

def dividir(a: Int, b: Int): Int = {
  val dividendo = a
  val divisor = b
  dividendo / divisor
}

dividir(2, 3)

La ultima expresión en el cuerpo del método es el valor de retorno del mismo. (Scala tiene una palabra reservada return, pero se usa raramente y no se aconseja usarla)

Otra forma de definir funciones

Los métodos también pueden tener expresiones de varias líneas.

def isAdult(age: Int): Boolean = {
  if (age >= 18) {
    true // La persona es mayor de edad
  } else {
    false // La persona es menor de edad
  }
}

Otra forma de definir funciones

Las funciones se pueden simplificar en una expresión

def isAdult(age: Int): Boolean = if (age >= 18) true else false

Otra forma de definir funciones

Se puede realizar operaciones con cadenas

def countWithoutOpenVowels(word : String) : Int = { 
   word.toLowerCase.replaceAll("a", "").replaceAll("e", "").replaceAll("o", "").length
}

Funciones matemáticas a código

Funciones matemáticas básicas

Implementar las siguientes funciones

  • f(x) = 2x + 3
  • g(x) = x²
  • h(x) = √x
  • Composición: (g ∘ f)(x)

Funciones matemáticas

El paradigma de la Programación Funcional (FP) se fundamenta en una premisa simple pero de gran alcance: construir programas utilizando exclusivamente funciones puras. En esencia, la FP es una disciplina que lleva lo que muchos consideran buenas prácticas de programación hasta su punto lógico

Funciones matemáticas

Traducción matemática en código

Funciones matemáticas a código. Expresiones

Funciones matemáticas a código.

Funciones matemáticas a código.

Definir función que tome un entero n y calcule el factorial de n

Funciones matemáticas a código.

Definir función que tome un entero n y calcule el factorial de n

Otra casos de funciones matemáticas

Traducción matemática en código

def g(n: Int) = (1 to n).map(k => k*k).sum
\sum_{k=1}^{n} k^2

Otra casos de funciones matemáticas

Traducción matemática en código

def g(n: Int): Double = math.pow((1 to n).product, 3) + (2* math.pow(n, 1.0/n))
f(n) = \left( \prod_{i=1}^{n} i \right)^3 + 2n^{\frac{1}{n}}

Trabajo de consulta

Trabajo de consulta

¿Qué son las funciones anónimas?

B1S2 Funciones

By Santiago Quiñones Cuenca

B1S2 Funciones

Programación funcional - funciones

  • 468