En programación funcional, un funtor es una estructura de datos que sabe cómo aplicar una función a los valores que contiene, sin que tengamos que preocuparnos por los detalles internos.
En Elm, el concepto de funtor aparece principalmente con el uso de map en distintos tipos.
¿Qué es un funtor?
En términos simples:
Un funtor es algo sobre lo que podemos hacer map.
Nos permite aplicar una función a un valor dentro de un contexto (List, Maybe, Result, etc.).
Veamos unos ejemplos:
Maybe como List:
dobles : List Int
dobles =
List.map (\x -> x * 2) [1, 2, 3]
-- Resultado: [2, 4, 6]
Acá List es un funtor, porque podemos aplicar una función a todos sus elementos usando map.
Maybe como funtor:
incrementar : Maybe Int -> Maybe Int
incrementar valor =
Maybe.map (\x -> x + 1) valor
-- incrementar (Just 5) == Just 6
-- incrementar Nothing == Nothing
El map de Maybe aplica la función solo si hay un valor (Just), y deja todo igual si es Nothing.
Result como funtor
toUppercase : Result String String -> Result String String
toUppercase resultado =
Result.map String.toUpper resultado
-- toUppercase (Ok "elm") == Ok "ELM"
-- toUppercase (Err "Error") == Err "Error"
El map de Result aplica la función al valor exitoso (Ok), y en caso de error (Err) no hace nada.
Todo funtor debe cumplir dos leyes:
1. Identidad:
List.map identity xs == xs
Aplicar la función identity no debe cambiar nada.
2. Composición:
List.map (f >> g) xs == (List.map f >> List.map g) xs
Aplicar dos funciones compuestas debe ser lo mismo que aplicarlas de a una.
En Elm, los funtores nos permiten:
- Aplicar funciones de forma elegante a valores dentro de contextos.
- Evitar escribir lógica repetida para casos como Nothing o Err.
- Pensar en términos más declarativos y expresivos.
Siempre que uses map en List, Maybe o Result, ¡estás usando funtores en Elm!