Programación funcional en Swift: nivel avanzado

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 Swift: nivel avanzado



Swift fue diseñado originalmente como un lenguaje multiparadigma, lo que lo convierte en una plataforma ideal para aplicar técnicas avanzadas de programación funcional. En este artículo exploraremos conceptos que van más allá de los closures básicos y map/filter/reduce — hablaremos de functores, mónadas, composición de funciones, currying y memoización. Estas herramientas te ayudarán a escribir código más predecible, testeable y expresivo para aplicaciones iOS y macOS.



Functores y mónadas: trabajando con contextos



Un functor es un tipo que implementa la función map, permitiendo aplicar una transformación al valor dentro de un contexto. En Swift, los ejemplos clásicos de functores son Optional y Array.



// Functor Optionallet value: Int? = 42let result = value.map { $0 * 2 } // Optional(84)

// Functor Arraylet numbers = [1, 2, 3]let doubled = numbers.map { $0 * 2 } // [2, 4, 6]


Una mónada es un functor con una operación adicional flatMap (o >>= en Haskell). Permite "desenvolver" contextos anidados. Swift soporta mónadas implícitamente a través del protocolo Monad, pero los tipos clave (Optional, Result, Async) implementan esta lógica.



// Mónada Optional: cadena de operaciones con posible nilfunc parseNumber(_ string: String) -> Int? { return Int(string) }func half(_ number: Int) -> Int? { return number % 2 == 0 ? number / 2 : nil }

let input = "42"let result = input.flatMap(parseNumber).flatMap(half) // Optional(21)

// Mónada Result para manejo de erroresenum AppError: Error { case invalidInput }func safeDivide(_ a: Int, _ b: Int) -> Result<Int, AppError> { guard b != 0 else { return .failure(.invalidInput) } return .success(a / b)}

let divisionResult = safeDivide(10, 2).flatMap { safeDivide($0, 1) } // .success(5)


Aplicación avanzada: creación de un tipo monádico propio para trabajar con operaciones asíncronas.



struct Async<T> {    let run: (@escaping (T) -> Void) -> Void        func map<U>(transform: @escaping (T) -> U) -> Async<U> {        return Async<U> { callback in            self.run { value in callback(transform(value)) }        }    }        func flatMap<U>(transform: @escaping (T) -> Async<U>) -> Async<U> {        return Async<U> { callback in            self.run { value in transform(value).run(callback) }        }    }}


Composición de funciones: construyendo pipelines



La composición de funciones es la creación de una nueva función mediante la aplicación secuencial de varias funciones. En Swift, esto se puede implementar mediante un operador o closures.



// Operador de composiciónprecedencegroup CompositionPrecedence {    associativity: left    higherThan: FunctionArrowPrecedence}

infix operator >>> : CompositionPrecedence

func >>>(_ f: @escaping (A) -> B, _ g: @escaping (B) -> C) -> (A) -> C { return { x in g(f(x)) }}

// Ejemplo: validación y formateolet trimWhitespace: (String) -> String = { $0.trimmingCharacters(in: .whitespaces) }let capitalize: (String) -> String = { $0.capitalized }let addExclamation: (String) -> String = { $0 + "!" }

let processString = trimWhitespace >>> capitalize >>> addExclamationprint(processString(" hello world ")) // "Hello World!"


La composición es especialmente útil al trabajar con cadenas de transformaciones de datos, por ejemplo, al procesar respuestas de red.



// Composición avanzada con manejo de errorestypealias ResultFunction = (T) -> Result<U, Error>

func compose(_ f: @escaping ResultFunction<T, U>, _ g: @escaping ResultFunction<U, V>) -> ResultFunction<T, V> { return { input

Blogs

Book Recommendations