En la programación funcional, una mónada (monad en inglés), es un patrón de diseño que representa cálculos definidos como una secuencia de pasos, permitiendo componer funciones con tipos incompatibles encapsulándolos en un tipo monádico. Un tipo de dato con una estructura mónada define lo que simboliza en un bloque de código, o anida funciones del mismo tipo. Esto le permite al programador crear tuberías informáticas que procesan datos en pasos, a los cuales se les asocia un decorador con reglas de proceso adicionales provistas por la mónada.O'Sullivan, Bryan; Goerzen, John; Stewart, Don. Real World Haskell. O'Reilly, 2009. ch. 14. Por lo tanto, las mónadas han sido descritas como un “punto y coma programable”; un punto y coma, siendo el operador usado para unir varias declaraciones en la programación imperativa, en consecuencia la expresión implica que código extra será ejecutado entre las declaraciones de una tubería. Las mónadas también han sido explicadas con una metáfora física, donde se comportan como una línea de ensamblaje, en las que un objeto transporta datos entre unidades funcionales que la van transformando un paso a la vez. También se las puede ver como un patrón de diseño funcional para construir tipos genéricos.
Los programas puramente funcionales pueden usar las mónadas para estructurar procedimientos que incluyan operaciones en secuencia como aquellos encontrados en la programación estructurada.Wadler, Philip. Comprehending Monads. Proceedings of the 1990 ACM Conference on LISP and Functional Programming, Nice. 1990.Wadler, Philip. The Essence of Functional Programming. Conference Record of the Nineteenth Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages. 1992. Muchos conceptos de programación comunes pueden ser descritos en términos de estructuras de mónadas, incluyendo los efectos secundarios, la Entrada/salida, asignación de variables, el manejo de excepciones, el analizador sintáctico, la programación no determinística, concurrencia y continuaciones. Esto permite que tales conceptos sean definidos en maneras puramente funcionales sin el uso de extensiones a la semántica del lenguaje. Los lenguajes como Haskell proveen mónadas en el núcleo estándar, permitiendo a los programadores reutilizar largas partes de su definición formal y aplicar en diversas librerías las mismas interfaces para combinar funciones.Hughes, J. (2005). Programming with arrows. In Advanced Functional Programming (pp. 73-129). Springer Berlin Heidelberg. "
Formalmente , una mónada consiste de un constructor de tipo M y dos operaciones , unir y retorno (donde retorno es a veces conocido como unidad). Las operaciones deben cumplir con ciertas propiedades para permitir la composición correcta de funciones monádicas (es decir, funciones que usen valores de la mónada como sus argumentos o valores de retorno). La operación retorno toma una valor de un tipo plano y lo pone en un contenedor monádico usando el constructor, creando así un valor monádico. La operación unir realiza el proceso inverso, extrayendo el valor original del contenedor y pasándolo a la siguiente función asociada en la tubería, posiblemente con chequeos adicionales y transformaciones. Dado que una mónada puede insertar operaciones adicionales en el dominio lógico del programa, se les puede considerar como un tipo de programación orientada a aspectos.De Meuter, Wolfgang. "Monads as a theoretical foundation for AOP". Workshop on Aspect Oriented Programming, ECOOP 1997. La lógica de negocio puede ser definida por la programación de aplicaciones en la tubería, mientras que las operaciones a ser repetidas muchas veces pueden ser operadas por una mónada predefinida construida previamente .
El nombre y concepto viene del epónimo (mónada) en la teoría de categorías, donde las mónadas son un tipo de funtor, o sea un mapeo entre categorías; aunque el término mónada en el contexto de la programación funcional es usualmente tomado como correspondiente al término mónada fuerte en la teoría de categorías.
Historia El concepto de mónada en la programación apareció en los '80 en el lenguaje Opal, aunque se le llamaban “comandos” y nunca fueron formalmente especificados. Eugenio Moggi fue el que por primera vez describió el uso general de las mónadas para estructurar programas en 1991. Mucha gente continuó su trabajo, incluyendo investigadores de lenguajes de programación como Philip Wadler y Simon Peyton Jones (los cuales estuvieron involucrados en la especificación de Haskell) Versiones tempranas de Haskell usaron una problemática “lista perezosa” para I/O, y Haskell 1.3 introdujo mónadas de una manera más flexible al combinar entrada/salida con evaluación perezosa.
En adición a la entrada/salida, los investigadores de los lenguajes de programación y diseñadores de librerías de Haskell han exitosamente aplicado las mónadas a evaluadores sintácticos y a intérpretes de lenguajes de programación. El concepto de las mónadas junto con el de la notación do de Haskell ha sido generalizada para formar funtores aplicativos y flechas.
Por un largo tiempo, Haskell y sus derivados han sido los únicos usuarios mayores de mónadas en la programación. También existen formulaciones en Scheme, Perl, Python, Racket, Clojure y Scala, donde las mónadas se han presentado como una opción de diseño de un nuevo lenguaje de programación. Recientemente F# ha incluido la característica de contener expresiones de cómputo o workflows, los cuales son un intento por introducir las construcciones monádicas dentro de una sintaxis más palpable a los programadores con una experiencia en los lenguajes imperativos.
Ejemplos motivantes El lenguaje de programación Haskell es un lenguaje funcional que hace un uso intensivo de mónadas e incluye azúcar sintáctico para hacer la composición de mónadas más conveniente. Todos los ejemplos de código escritos aquí son escritos en Haskell, a menos que se indique lo contrario.
Se demuestran dos ejemplos comunes en la introducción a las mónadas: la mónada Maybe y la mónada IO. Las mónadas están desde luego, no recluidas al lenguaje Haskell, el segundo ejemplo muestra la mónada Writer en JavaScript.
La mónada Maybe Considérese la opción de tipo Maybe a (“tal vez un”), representando un valor que es o un valor del tipo a , o ninguno. Para distinguirlos, se tienen dos constructores de tipo de dato algebraico: Just t, conteniendo el valor t, o Nothing, sin contenido. data Maybe t = Just t | Nothing
Nos gustaría poder usar este tipo como una simple excepción chequeada: en cualquier punto del cómputo, este puede fallar, lo que causa que el resto del proceso sea saltado y que el resultado final sea Nothing. Si todos los pasos del cómputo son exitosos, entonces el resultado final es Just x para un valor x.
En el siguiente ejemplo, suma es una función que toma dos argumentos del tipo Maybe int, y regresa un resultado del mismo tipo. Si ambas mx y my tienen valores Just, queremos regresar Just su suma; pero si mx o my son Nothing, queremos regresar Nothing. Si se intentara escribir funciones con este tipo de conducta, se terminaría con una serie de casos “if Nothing then Nothing else something with x in Just x” que rápidamente se volverían confusos: suma :: Maybe Int -> Maybe Int -> Maybe Int suma mx my = case mx of Nothing -> Nothing Just x -> case my of Nothing -> Nothing Just y -> Just (x + y)
Para aliviar esto, podemos definir operaciones para encadenar tales cómputos de manera conjunta. El operador binario bind (“unir”) (>>=) encadena los resultados de un cómputo que pudiera fallar, a una función que elige otro cómputo que pudiera fallar. Si el argumento es Nothing (“nada”), el segundo argumento (la función) es ignorada y la operación entera simplemente falla. Si el argumento es Just x (“solo x”), pasamos x a la función para obtener un nuevo valor Maybe, que puede o no ser el resultado en un valor del tipo Just (“solo”).
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b Nothing >>= _ = Nothing -- Un cómputo fallido regresa Nada (Just x) >>= f = f x -- Aplica la función f al valor x
Usando un poco de azúcar sintáctico, conocida como notación do, el ejemplo puede ser escrito como: suma :: Maybe Int -> Maybe Int -> Maybe Int suma mx my = do x <- mx y <- my return (x + y)
Dado que este tipo de operación es muy común, existe una función estándar en Haskell (liftM2) que toma dos valores monádicos (aquí: dos Maybes) y combina sus contenidos (dos números) usando otra función (adición), haciendo posible escribir el ejemplo pasado como: add :: Maybe Int -> Maybe Int -> Maybe Int add = liftM2 (+)
La mónada escritora La mónada escritora permite que un proceso lleve información adicional “al lado” de su valor de cómputo. Esto puede ser útil para el registro de errores o el debugging de la información que no es el resultado primario.
El siguiente ejemplo implementa la mónada escrita en JavaScript:
Primero, una mónada escritora es definida. La función unidad crea un nuevo tipo de valor de un tipo básico, el cual lleva una cadena de registro; y bind aplica la función a un valor viejo, y finalmente regresa el nuevo valor de resultado con un registro expandido. Los corchetes trabajan aquí como el constructor de tipo de la mónada, creando un valor de tipo monádico para la mónada escritora, hecha de componentes más simples (el valor en la posición 0 del arreglo, y la cadena de registro en la posición 1).
var unit = function (value) { return [value, ''] };
var bind = function (valorMonadico, transformaConRegistro) { var value = valorMonadico, registro = valorMonadico, result = transformaConRegistro(value); return [result, registro + result];
Tubería es una función auxiliar que concatena una secuencia de binds aplicados a un arreglo de funciones.
var pipeline = function (monadicValue, functions) { for (var key in functions) { monadicValue = bind(monadicValue, functions[key]);
return monadicValue;
Ejemplos de funciones que regresen valores del tipo esperados por la mónada escritora de arriba: var squared = function (x) { return [x * x, 'al cuadrado.'];
var halved = function (x) { return [x / 2, 'a la mitad.'];
Finalmente, un ejemplo del uso de la mónada para crear una tubería de funciones matemáticas, con información de debug al lado. pipeline(unit(4), [squared, halved]); // [8, "al cuadrado.a la mitad"]
La mónada IO
En un lenguaje puramente funcional, como Haskell, las funciones no pueden tener efectos externos visibles como parte de la semántica de la función. Aunque una función no puede directamente causar un efecto, puede construir un valor describiendo un efecto deseado, que el llamante puede aplicar a un tiempo conveniente. .Peyton Jones, Simon L.; Wadler, Philip. Imperative Functional Programming. Conference record of the Twentieth Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, Charleston, South Carolina. 1993 En la notación Haskell, un valor de tipo IO a representa una acción que, a la hora de ser realizada , produce un valor de tipo a.
Podemos pensar en un valor de tipo IO como una acción que toma como su argumento el estado actual del mundo, y que regresara un nuevo mundo donde el estado ha sido cambiado de acuerdo al valor de retorno de la función. Por ejemplo, las funciones doesFileExist (existe el archivo?) y removeFile (borra el archivo) en la librería estándar de Haskell tienen los siguientes tipos
doesFileExist :: FilePath -> IO Bool removeFile :: FilePath -> IO ()
Así que uno puede pensar removeFile como una función que, dado un FilePath, regresa una acción IO ; esta acción se encargará de que el mundo, en este caso el sistema de archivos, no tendrá un archivo nombrado por tal FilePath cuando sea ejecutado. Aquí el valor interno IO es del tipo () que significa que el llamante no está interesado en otros resultados. Por otra parte, en