Programación funcional en C#: principios y ejemplos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Programación funcional en C#: de la teoría a la práctica

La programación funcional (PF) es un paradigma en el que los cálculos se consideran como la evaluación de funciones matemáticas, evitando cambios de estado y datos mutables. Aunque C# originalmente era un lenguaje orientado a objetos, a partir de la versión 3.0 ha ido incorporando activamente capacidades funcionales. Hoy en día, C# admite conceptos como expresiones lambda, LINQ, tipos inmutables e incluso pattern matching. En este artículo analizaremos los principios clave de la PF y mostraremos cómo aplicarlos en proyectos reales con C#.



1. Funciones puras y ausencia de efectos secundarios

Función pura es una función que:

  • Siempre devuelve el mismo resultado para los mismos argumentos (transparencia referencial).
  • No tiene efectos secundarios (no modifica el estado global, no escribe en archivos, no envía solicitudes HTTP).

En C#, una función pura puede verse así:

public static int Add(int a, int b) => a + b;

Y aquí un ejemplo de función impura:

public static int AddAndLog(int a, int b){    Console.WriteLine($"Sumando {a} y {b}"); // efecto secundario    return a + b;}

Ventajas de las funciones puras: son fáciles de probar, depurar y paralelizar.



2. Inmutabilidad (Immutability)

En PF, los datos son inmutables por defecto. En C# se utilizan para esto:

  • La palabra clave readonly para campos.
  • Las estructuras record (C# 9+), que crean automáticamente objetos inmutables.
  • Las colecciones del espacio de nombres System.Collections.Immutable.

Ejemplo con record:

public record Person(string Name, int Age);

Si se necesita cambiar la edad, se crea una nueva instancia:

Person person = new("Iván", 30);Person olderPerson = person with { Age = 31 };

La inmutabilidad previene mutaciones accidentales y simplifica la concurrencia.



3. Funciones de orden superior y expresiones lambda

Las funciones de orden superior toman otras funciones como argumentos o las devuelven. En C# esto se implementa mediante delegados: Func<>, Action<>, Predicate<>.

Un ejemplo simple es el método Where de LINQ:

List<int> numbers = new() { 1, 2, 3, 4, 5 };var evenNumbers = numbers.Where(n => n % 2 == 0).ToList();

Aquí n => n % 2 == 0 es una expresión lambda (función anónima).

Se puede escribir una función de orden superior propia:

public static List<T> Filter<T>(List<T> list, Func<T, bool> predicate){    var result = new List<T>();    foreach (var item in list)        if (predicate(item)) result.Add(item);    return result;}


4. LINQ: potente herramienta de estilo funcional

LINQ (Language Integrated Query) es, quizás, el ejemplo más destacado de programación funcional en C#. Permite procesar colecciones de forma declarativa, como en SQL.

Ejemplo: obtener los nombres de usuarios mayores de 18 años, ordenados por edad:

var users = new List<User>{    new("Ana", 22),    new("Boris", 17),    new("Víctor", 30)};

var result = users .Where(u => u.Age >= 18) .OrderBy(u => u.Age) .Select(u => u.Name) .ToList();

LINQ admite ejecución diferida (lazy evaluation), lo que ahorra recursos.



5. Mónadas y tipo Maybe en C#

Las mónadas son una abstracción para cadenas de cálculos con contexto (por ejemplo, manejo de null o asincronía). En C# no hay una mónada Maybe incorporada, pero es fácil de implementar:

public class Maybe<T>{    private readonly T _value;    public bool HasValue { get; }        p                

Blogs

Book Recommendations