Librería mo para Go: Mónadas y patrones funcionales
¡Bienvenido al mundo de la programación funcional en Go! La librería mo (de mónadas) es una herramienta potente que introduce en el lenguaje imperativo Go conceptos de mónadas y patrones funcionales populares en Haskell, Scala y Rust. Si alguna vez te has enfrentado al problema de manejar errores con if err != nil, interminables comprobaciones de nil o cadenas de llamadas engorrosas, mo te ofrece una solución elegante.
El objetivo principal de la librería es proporcionar contenedores type-safe (Option, Result, Either) que encapsulan estados posibles (presencia/ausencia de valor, éxito/error) y permiten trabajar con ellos de forma funcional. En lugar de escribir decenas de condicionales, construyes cadenas de transformaciones donde cada paso se maneja automáticamente. Esto hace que el código sea más legible, predecible y menos propenso a errores, especialmente en lógicas de negocio complejas.
La librería mo no intenta convertir Go en Haskell. Ofrece un enfoque pragmático: usas patrones funcionales donde realmente simplifican el código, manteniendo la sintaxis familiar de Go. mo es especialmente útil para el manejo de errores, trabajo con valores opcionales, composición de funciones e implementación de pipelines de procesamiento de datos. Se combina bien con gorutinas y canales, permitiendo construir programas concurrentes robustos.
Instalación
La instalación de la librería mo se realiza de la forma estándar en Go a través del gestor de paquetes go get. Ejecuta el siguiente comando en la terminal, en la raíz de tu proyecto (donde se encuentra go.mod):
go get github.com/samber/mo
Después de ejecutar este comando, la librería se añadirá a tu archivo go.mod y podrás importarla en tus archivos de código fuente. Asegúrate de tener instalada la versión de Go 1.18 o superior (necesaria para el soporte de genéricos).
Inicio rápido
Comencemos con un ejemplo clásico: la división segura de dos números. En Go tradicional, devolveríamos un error. Con mo usamos el tipo Result, que puede ser Ok (éxito) o Err (error).
package main
import (
"fmt"
"github.com/samber/mo"
)
// safeDivide devuelve un Result que contiene el resultado de la división o un error.
func safeDivide(a, b float64) mo.Result[float64] {
if b == 0 {
return mo.Err[float64](fmt.Errorf("división por cero"))
}
return mo.Ok(a / b)
}
func main() {
result := safeDivide(10, 2)
// Usamos el método Match para manejar ambos casos.
result.Match(
func(value float64) {
fmt.Printf("Resultado: %.2f\n", value)
},
func(err error) {
fmt.Printf("Error: %s\n", err)
},
)
// Probamos la división por cero.
result2 := safeDivide(10, 0)
result2.Match(
func(value float64) {
fmt.Printf("Resultado: %.2f\n", value)
},
func(err error) {
fmt.Printf("Error: %s\n", err)
},
)
}
Este ejemplo muestra la idea básica: en lugar de comprobar el error manualmente, delegamos la responsabilidad del manejo a la librería usando el método Match.
Métodos y funciones principales
A continuación, se presentan los componentes clave de la librería mo. Veremos 8 métodos/tipos principales que cubrirán el 90% de tus necesidades.
1. mo.Ok[T any] y mo.Err[T any]
Firma:
func Ok[T any](value T) Result[T]func Err[T any](err error) Result[T]
Qué hacen: Crean e