Scala V: introducción a Mónadas

En la presente entrada, Scala V: introducción a Mónadas, realizaré una descripción de qué es una mónada y cómo aplicarlo con Scalaz.

Definimos mónada como una extensión o herencia de un Functor. La mónada es la solución al siguiente problema: sea aquel valor de entrada que se ejecuta en un contexto con una función el cual genera un valor de salida; y, este valor de salida, es aplicado como valor de entrada en otro contexto para una función la cual genera un valor de salida; y, est valor de salida, es usado como entrada en otro contexto con una función la cual genera una valor de salida y, así, sucesivamente. Desde un punto de vista mas abstracto y orientado a la programación estructurada, es la sucesión de sentencias que se van ejecutando de forma secuencial.

La mónada cumple la propiedad de identidad o unitaria y la propiedad asociativa.

La definición de Mónada en Scalaz hereda de Applicative y de Bind, estudiado en las entradas de functores. La definición es la siguiente:

trait Monad[F[_]] extends Applicative[F] with Bind[F] { self =>
}

La función principal de una mónada es la función flatMap y, en Scalaz, se definen alias de funciones de la función flatMap. La definición de las operaciones se define en BindOps como sigue:

/** Wraps a value `self` and provides methods related to `Bind` */
trait BindOps[F[_],A] extends Ops[F[A]] {
  implicit def F: Bind[F]
  ////
  import Liskov.<~<
  def flatMap[B](f: A => F[B]) = F.bind(self)(f)
  def >>=[B](f: A => F[B]) = F.bind(self)(f)
  def ∗[B](f: A => F[B]) = F.bind(self)(f)
  def join[B](implicit ev: A <~< F[B]): F[B] = F.bind(self)(ev(_))
  def μ[B](implicit ev: A <~< F[B]): F[B] = F.bind(self)(ev(_))
  def >>[B](b: F[B]): F[B] = F.bind(self)(_ => b)
  def ifM[B](ifTrue: => F[B], ifFalse: => F[B])(implicit ev: A <~< Boolean): F[B] = {
    val value: F[Boolean] = Liskov.co[F, A, Boolean](ev)(self)
    F.ifM(value, ifTrue, ifFalse)
  }
 ////
}

Las importaciones necesarias para trabajar con Mónadas en Scalaz son las siguientes:

 import scalaz.Monad
 import scalaz.Scalaz.

Ejemplo de mónadas

En los siguientes apartados, se muestran unos ejemplos de mónadas con la función flatMap y sus funciones alias.

Ejemplo de función flatMap

 println(s"3.some flatMap { x => (x + 1).some } }=${ 3.some flatMap { x => (x + 1).some } }")

La salida por consola es la siguiente:

 3.some flatMap { x => (x + 1).some } }=Some(4)

Ejemplo de función >>=, alias de flatMap

 println(s"3.some >>= { x => (x + 1).some } }=${ 3.some >>= { x => (x + 1).some } }")
 val monadOption2 = Monad[Option].point("Palabra") >>= { (elem:String) => Some(elem + " lo añadido") }
 println(s"Monad[Option].point('Palabra') >>= { (elem:String) => Some(elem + ' lo añadido') }=${monadOption2}")
 val monadOption3 = Monad[Option].point(10) >>= { (elem:Int) => Some(elem + 369) }
 println(s"Monad[Int].point(10) flatMap { (elem:Int) => elem + 369 }=${monadOption3}")

La salida por consola es la siguiente:

 3.some >>= { x => (x + 1).some } }=Some(4)
 Monad[Option].point('Palabra') >>= { (elem:String) => Some(elem + ' lo añadido') }=Some(Palabra lo añadido) 
 Monad[Int].point(10) flatMap { (elem:Int) => elem + 369 }=Some(379)

Ejemplo de función ∗, alias de flatMap

 println(s"3.some ∗ { x => (x + 1).some } }=${ 3.some ∗ { x => (x + 1).some } }")

La salida por consola es la siguiente:

 3.some ∗ { x => (x + 1).some } }=Some(4)

Función unaria point de Monad.

 val monadOption1 = Monad[Option].point("Palabra")
 println(s"Monad[Option].point('Palabra') =${ monadOption1 }")

La salida por consola es la siguiente:

 Monad[Option].point('Palabra') =Some(Palabra)

Función condicional de Monad.

 val monadOption4 = Monad[Option].ifM(Some(3<4), Some("3 menor de 4"), Some("error en la condición"))
 println(s"Monad[Option].ifM(Some(3<4), Some('3 menor de 4'), Some('error en la condición'))=${monadOption4}")
 val monadOption5 = Monad[Option].ifM(Some(3>4), Some("3 menor de 4"), Some("error en la condición"))
 println(s"Monad[Option].ifM(Some(3>4), Some('3 menor de 4'), Some('error en la condición'))=${monadOption5}")

La salida por consola es la siguiente:

 Monad[Option].ifM(Some(3<4), Some('3 menor de 4'), Some('error en la condición'))=Some(3 menor de 4)
 Monad[Option].ifM(Some(3>4), Some('3 menor de 4'), Some('error en la condición'))=Some(error en la condición)

Para el lector interesado, las entradas que he realizado sobre Scalaz son las siguientes:

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 )

Google+ photo

Estás comentando usando tu cuenta de Google+. 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 )

w

Conectando a %s