Teoría de Cate-movidas: Mónadas

Hoy ha llegado el día. Hoy veremos unas pinceladas de las famosas mónadas.
Una mónada, al igual que un monoide, parece un concepto sacado de lo más profundo del infierno. Parece imposible de entender. Pero nada más lejos de la realidad. Vamos a intentar poner un poco de luz sobre este concepto.

Existen numerosas definiciones de lo que es una mónada. Alguna más complicada, alguna más sencilla.

44b0bd758f8ee5c81362923f0d5c8e017c9ddf623925e60c29a4c015b89fbb45

Pero como nos gustan las definiciones sencillas, en este primer contacto con las mónadas vamos a decir que son estructuras algebraicas que tienen un constructor y un método flatMap que, como vimos en anteriores posts, es la concatenación de un método map y un flatten.

¿Qué necesitamos para crear una mónada?

Como acabamos de comentar, básicamente necesitamos dos métodos: un constructor (comúnmente llamado apply) y un método flatMap.

Además, existen unas leyes monádicas que hay que cumplir. Dichas leyes exigen una serie de relaciones entre las funciones anteriormente mencionadas. Pero, para bien o para mal, no vamos a analizarlas en este post para no hacerlo muy denso.

Ejemplo: El tipo Option

El tipo Option, como ya hemos dicho en varios post, es una mónada.

Bdu68sACYAAfkkr

Vamos a introducirnos en las tripas de Scala para ver como está definida:

def apply[A](x: A): Option[A] =
  if (x == null) None else Some(x)

def flatMap[B](f: A => Option[B]): Option[B] =
  if (isEmpty) None else f(this.get)

Como se puede ver, el tipo Option tiene un constructor (apply) y un método flatMap. Gracias a estos dos métodos (y a que se cumplen las leyes monádicas), podemos decir que el tipo Option es una mónada.

Sin embargo, en la librería básica de Scala, no está definido directamente el tipo Monad. Pero para eso está Scalaz. Vamos a ver como define Scalaz el tipo Option como mónada:

def point[A](a: => A) = Some(a)

def bind[A, B](fa: Option[A])(f: A => Option[B]) =
  fa flatMap f

Como se puede ver, en Scalaz, el método flatMap es llamado bind. A su vez, el método point llama a un constructor, por lo que realmente se llama al método apply. Por tanto, si definimos estos dos métodos para nuestros tipos propios (y además cumplen las leyes monádicas), podemos definir nuestras propias mónadas.

Y debido a que tiene definida una función flatMap y un método apply (o lo que es lo mismo, un método bind y un método point), podemos utilizar for comprehension para hacer nuestro código más legible, como vimos hace dos semanas:

for {
  x <- Some(1)
  y <- Some(2)
} yield x + y //Some(3)

Conclusión

Las mónadas son mucho más de lo que hemos contado en este post. Es todo un mundo por explorar. Además de las ya mencionadas leyes monádicas, existen distintos tipos de mónadas ya definidas, como la mónada Reader. Además, el uso de mónadas está orientado a evitar los efectos de lado, un tema bastante importante en el ámbito de la programación funcional pura. Pero todo a su tiempo 🙂

Anuncios

6 thoughts on “Teoría de Cate-movidas: Mónadas

    • Uno de los usos más importantes de las mónadas es la posibilidad de combinación que tienen entre ellas gracias al método flatmap. Por ejemplo, mediante la mónada Reader (que encontrarás en otro post de este blog), puede combinar varias funciones de tipo Function1, es decir, que solo tienen un argumento de entrada.

      En este post se comenta de forma muy breve otro ejemplo de combinación mediante el tipo Option. Si se tienen varias instancias de tipo Option, pueden combinarse entre si utilizando una for comprehension. Si utilizamos otro tipo que sea mónada (o bien nos creamos un tipo propio que lo sea) podemos combinar dichas mónadas de igual manera.

      Podemos beneficiarnos de esta capacidad de combinación para ir creando cada vez funciones más complicadas sin la necesidad de tener que evaluar el resultado.

      Si estás interesado te recomiendo este post sobre mónadas en Scala que implementa ejemplos propios y realiza una explicación más extensa: http://scabl.blogspot.com.es/2013/02/monads-in-scala-1.html

      Me gusta

      • Muchas gracias, no me habia llegado el aviso de tu respuesta. muy interesante que el flatmap tenga que cepillarse los nulls/none tambien 🙂

        Me gusta

  1. Las monadas no son mas que un patrón de diseño para la composición de funciones en lenguajes funcionales. Se trate de envolver todo en un contexto y aplicarle “transformaciones (funciones)” a lo que esta dentro de ese envoltorio. Eso nos permite manejar los errores de una manera mas sencilla (con la monada maybe), la programación asíncrona y la entrada/salida. No conozco Scala pero algo sencillo puede ser esto en javascript (aclaro que esto es un funtor no una monada, pero es la base para entenderlas).

    var Contenedor = function(item) {
    this.__item = item;
    }

    Contenedor.prototype.of = function(item) //Aqui la clave de todo
    { //Siempre que se cree un nuevo objeto con este metodo
    return new Contenedor (item); //el valor sera envuelto y nunca dejara de estarlo
    }

    Contenedor.prototype.map = function(fn){ //Esta función “desenvuelve” el ítem del contexto, le
    return Contenedor.of ( fn ( this.__item)); //aplica la función pasada como argumento y
    } //retorna el resultado envuelto en un nuevo contexto

    Y la forma de uso seria.

    var elemento = Contenedor.of(“Un simple string”);

    elemento.map(toUpperCase)
    .map(substr(0,2)
    .map(console.log);

    La idea de esto, es que todas las funciones que modifiquen el item sean pasadas a trabes de map (o como lo quieran llamar). De esta manera nos aseguramos que nuestros datos o puedan ser modificados “accidentalmente” por ninguna función fuera del contexto.

    La gracia de esto es que map se puede modificar del modo que deseemos ( funciona como una especie de decorador en python ). Un ej sencillo:

    Contenedor.prototype.map = function(fn){
    console.log(“La funcion “, fn.name, ” a sido llamada”);
    return Contenedor.of ( fn ( this.__item));
    }

    La idea de las monadas es la de emparejar los argumentos de entrada con los de retorno, permitiéndonos de esa manera poder componer funciones sin importar la cantidad de argumentos que tenga cada una.

    Un saludo grande y espero poder haber arrojado algo de luz sobre el tema.

    Me gusta

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s