31. Operaciones y composición de funciones

Las funciones pueden combinarse para construir nuevas funciones. La composición aplica una función después de otra y permite modelar transformaciones encadenadas de datos.

31.1 Introducción

Las funciones permiten transformar elementos de un conjunto en elementos de otro. Cuando tenemos varias funciones, podemos combinarlas para formar nuevas transformaciones.

La operación más importante en teoría de conjuntos es la composición de funciones. En programación, esta idea aparece al encadenar transformaciones, validaciones, filtros y conversiones.

31.2 Recordatorio de función

Una función f: A → B asigna a cada elemento de A un único elemento de B.

f: A → B f(a) = b

El valor a pertenece al dominio y b pertenece al codominio.

31.3 Composición de funciones

Si tenemos dos funciones f: A → B y g: B → C, podemos componerlas para obtener una nueva función de A en C.

g ∘ f: A → C (g ∘ f)(x) = g(f(x))

Primero se aplica f y luego se aplica g.

31.4 El orden importa

La composición g ∘ f se lee "g compuesta con f", pero se aplica de derecha a izquierda: primero f, después g.

(g ∘ f)(x) = g(f(x))

En general, g ∘ f no es igual a f ∘ g.

31.5 Ejemplo numérico

Sean las funciones:

f(x) = x + 1 g(x) = x · 2

Entonces:

(g ∘ f)(3) = g(f(3)) = g(4) = 8 (f ∘ g)(3) = f(g(3)) = f(6) = 7

Los resultados son distintos, por eso el orden de composición importa.

31.6 Composición y compatibilidad

Para que g ∘ f tenga sentido, las salidas de f deben poder usarse como entradas de g.

f: A → B g: B → C

Si f produce valores fuera del dominio de g, la composición no está bien definida para todos los elementos.

31.7 Composición como pares ordenados

Si las funciones se representan como relaciones, la composición conecta pares compatibles.

f = {(1, a), (2, b)} g = {(a, x), (b, y)} g ∘ f = {(1, x), (2, y)}

El valor intermedio debe coincidir: 1 va a a, y a va a x; por lo tanto 1 va a x.

31.8 Función identidad

La función identidad sobre un conjunto A asigna cada elemento a sí mismo.

idA: A → A idA(x) = x

Componer una función con la identidad no cambia la función.

31.9 Propiedad de identidad

Si f: A → B, entonces:

f ∘ idA = f idB ∘ f = f

La identidad funciona como elemento neutro para la composición.

31.10 Asociatividad de la composición

La composición de funciones es asociativa. Si las composiciones están bien definidas, la forma de agrupar no cambia el resultado.

h ∘ (g ∘ f) = (h ∘ g) ∘ f

Aunque la composición no sea conmutativa, sí es asociativa.

31.11 Función inversa

Una función inversa deshace el efecto de otra función. Para que una función tenga inversa como función, debe ser biyectiva.

f: A → B f⁻¹: B → A

Si f(a) = b, entonces f⁻¹(b) = a.

31.12 Inversa y composición

Cuando una función tiene inversa, componerla con su inversa produce una función identidad.

f⁻¹ ∘ f = idA f ∘ f⁻¹ = idB

Esto expresa que una transformación y su inversa se cancelan mutuamente.

31.13 Composición en JavaScript

En JavaScript, la composición puede representarse creando una función que aplique dos funciones en secuencia.

function componer(g, f) {
  return function (x) {
    return g(f(x));
  };
}

const sumarUno = x => x + 1;
const duplicar = x => x * 2;

const duplicarDespuesDeSumar = componer(duplicar, sumarUno);

console.log(duplicarDespuesDeSumar(3));

Primero se aplica sumarUno y después duplicar.

31.14 El orden en JavaScript

Si invertimos el orden de composición, el resultado puede cambiar.

function componer(g, f) {
  return function (x) {
    return g(f(x));
  };
}

const sumarUno = x => x + 1;
const duplicar = x => x * 2;

const duplicarDespuesDeSumar = componer(duplicar, sumarUno);
const sumarDespuesDeDuplicar = componer(sumarUno, duplicar);

console.log(duplicarDespuesDeSumar(3));
console.log(sumarDespuesDeDuplicar(3));

Los resultados son 8 y 7, igual que en el ejemplo matemático.

31.15 Composición de varias funciones

Podemos componer una lista de funciones para crear una transformación más compleja.

const sumarUno = x => x + 1;
const duplicar = x => x * 2;

function componerVarias(...funciones) {
  return function (valorInicial) {
    return funciones.reduceRight((valor, funcion) => funcion(valor), valorInicial);
  };
}

const convertirATexto = x => `Resultado: ${x}`;
const proceso = componerVarias(convertirATexto, duplicar, sumarUno);

console.log(proceso(3));

La composición se aplica de derecha a izquierda: primero sumarUno, luego duplicar y finalmente convertirATexto.

31.16 Composición con pares ordenados en JavaScript

También podemos componer funciones representadas como relaciones de pares ordenados.

function componerRelaciones(g, f) {
  return f.map(([entrada, intermedio]) => {
    const par = g.find(([origen]) => origen === intermedio);
    return [entrada, par[1]];
  });
}

const f = [[1, "a"], [2, "b"]];
const g = [["a", "x"], ["b", "y"]];

console.log(componerRelaciones(g, f));

El resultado es la relación compuesta {(1, x), (2, y)}.

31.17 Aplicaciones prácticas

Área Composición Ejemplo
Transformación de datos Normalizar → validar → guardar Procesar formularios
Interfaces Evento → estado → vista Actualizar una pantalla
Matemática f seguida de g g(f(x))
APIs Datos crudos → formato → respuesta Preparar salida JSON
Seguridad Entrada → hash → codificación Transformaciones encadenadas

31.18 Errores frecuentes

  • Aplicar la composición en el orden incorrecto.
  • Suponer que g ∘ f siempre es igual a f ∘ g.
  • Componer funciones cuyos dominio y codominio no son compatibles.
  • Creer que toda función tiene inversa.
  • Olvidar que la composición sí es asociativa aunque no sea conmutativa.

31.19 Qué debes recordar de este tema

  • La composición g ∘ f significa aplicar primero f y luego g.
  • En general, la composición no es conmutativa.
  • La composición es asociativa.
  • La función identidad no cambia una función al componerla.
  • Una función tiene inversa como función si es biyectiva.
  • En JavaScript, la composición permite encadenar transformaciones de datos.

31.20 Conclusión

La composición permite construir funciones complejas a partir de funciones simples. Es una herramienta fundamental para razonar sobre transformaciones matemáticas y procesos de programación.

En el próximo tema estudiaremos álgebra de conjuntos.