Programação Funcional em Kotlin: Nível Avançado

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Programação Funcional em Kotlin: Nível Avançado

Kotlin é uma linguagem multiparadigma que combina organicamente abordagens orientadas a objetos e funcionais. Se você já domina os conceitos básicos de programação funcional (PF), como map, filter, fold e lambdas, é hora de mergulhar em técnicas avançadas. Neste artigo, abordaremos composição de funções, currying, lazy evaluation, além de conhecer functores e mônadas com exemplos em Kotlin. Todos os exemplos de código podem ser executados na sua IDE.



1. Composição de Funções e Currying

Composição é a criação de uma nova função através da aplicação sequencial de duas ou mais funções. Em Kotlin não há um operador nativo de composição como em Haskell, mas ele pode ser facilmente implementado via extension functions.



Exemplo de Composição de Funções

// Definindo funçõesval double: (Int) -> Int = { it * 2 }val increment: (Int) -> Int = { it + 1 }

// Composição: primeiro double, depois incrementinfix fun <A, B, C> ((B) -> C).compose(f: (A) -> B): (A) -> C = { a -> this(f(a)) }

val doubleThenIncrement = increment compose doubleprintln(doubleThenIncrement(5)) // 11 (5*2 + 1)


Currying

Currying é a transformação de uma função de múltiplos argumentos em uma cadeia de funções, cada uma com um único argumento. Em Kotlin, isso é implementado com lambdas aninhadas.

// Função normalfun sum(a: Int, b: Int): Int = a + b

// Versão curriedfun curriedSum(a: Int): (Int) -> Int = { b -> a + b }

val add5 = curriedSum(5)println(add5(3)) // 8

// Função universal para curryingfun <A, B, C> ((A, B) -> C).curry(): (A) -> (B) -> C = { a -> { b -> this(a, b) } }

val curriedSum2 = ::sum.curry()println(curriedSum2(10)(20)) // 30

Currying é especialmente útil ao trabalhar com aplicação parcial e fábricas de funções.



2. Functores e Mônadas: Teoria na Prática

Um functor é um contêiner que pode ser mapeado (map) usando uma função. Uma mônada é um functor com capacidade de composição de contêineres (flatMap). Em Kotlin, exemplos claros de mônadas são Result (ou Either) e Sequence.



Exemplo com Result (mônada Either)

data class User(val name: String, val email: String)

fun parseUser(json: String): Result<User> = runCatching { // Simulação de parsing if (json.isBlank()) throw IllegalArgumentException("Empty JSON") User("Alice", "alice@example.com")}

fun sendEmail(user: User): Result<String> = runCatching { if (user.email.contains("@")) "Email sent to ${user.email}" else throw IllegalArgumentException("Invalid email")}

// Cadeia monádicaval result = parseUser("{...}") .flatMap { user -> sendEmail(user) } .map { message -> "Success: $message" } .onFailure { error -> println("Error: ${error.message}") }

println(result.getOrDefault("Failed"))

Aqui, flatMap evita verificações aninhadas de sucesso/erro, tornando o código linear e legível.



Criando seu próprio functor: Tipo Option

sealed class Option<out T> {    data class Some<T>(val value: T) : Option<T>()    object None : Option<Nothing>()}

fun <T, R> Option<T>.map(f: (T) -> R): Option<R> = when (this) { is Option.Some -> Option.Some(f(value)) is Option.None -> Option.None}

fun <T, R> Option<T>.flatMap(f: (T) -> Option<R>): Option<R> = when (this) { is Option.Some -> f(value) is Option.None -> Option.None}

val maybeNumber: Option<Int> = Option.Some(42)val resultOption = maybeNumber .map { it * 2 } .flatMap { Option.Some("Value: $it") }

println(resultOption) // Some(value=Value: 84)

Blogs

Book Recommendations