Teoría de Cate-movidas: Monoides

Somos como las colecciones de soldaditos de plomo y las matrículas gratis en los gimnasios… ¡volvemos en Septiembre!
Y volvemos con algo que parece muy heavy pero que seguro que después de leer unas pocas líneas será más sencillo.
Hoy comenzamos con una serie de post en las que hablaremos de algunas abstracciones funcionales, muy relacionadas con el mundo de las matemáticas, con el objetivo de introducirnos poco a poco en el mundo de las librerías puramente funcionales de Scala, como pueden ser Scalaz y Cats. Para ello, vamos a apoyarnos en algunas características y técnicas que ya hemos tratado anteriormente, como por ejemplo, las type classes.

Por ello, hoy vamos a comenzar con los monoides.

Monoides, monoides everywhere…

¿Monoide? Un palabro un poco raro. Vamos a ver que dice Wikipedia sobre los monoides:

“Estructura algebraica con una operación binaria, que es asociativa y tiene elemento neutro, es decir, es un semigrupo con elemento neutro.”

i-dont-understand

Ah…si, claro. Ya lo pillo…… Vamos a analizarlo poco a poco.

  • Operación binaria: ok, eso lo entiendo. Es una operación con dos operandos. Para tener un convenio, llamaremos a esta operación de forma genérica con el símbolo |+|

Sin embargo, la operación binaria tiene que cumplir dos reglas:

  1. Debe cumplir la propiedad asociativa, es decir:  a |+| (b + c) = (a + b) |+| c
  2. Y además, debe tener un elemento neutro:   a |+| elementoNeutro = a

Mmmm, ya está más claro. Entonces, la suma de enteros cumple las reglas de los monoides:

  • Cumple la propiedad asociativa: 1 + (2 + 3) = (1+ 2) + 3
  • Tiene un elemento neutro, el cero: 1 + 0 = 1

Con la multiplicación de enteros pasa lo mismo (cuyo elemento neutro es el 1), y con la concatenación de cadenas de texto también (siendo la cadena vacía “”, el elemento neutro). Genial, ya voy entendiéndolo.

Monoides en Scalaz

Para trabajar con monoides vamos a utilizar en este post, la librería Scalaz. Scalaz ofrece un sin fin de opciones, abstracciones y funcionalidades. Hoy solo vamos a dar unas pequeñas pinceladas que nos permitirán realizar un ejemplo. Prometemos en un futuro hablar detenidamente de esta librería 🙂

Lo primero que tenemos que hacer es importar Scalaz en nuestro proyecto. Para ello, incluimos la dependencia en nuestro proyecto:

libraryDependencies += "org.scalaz" %% "scalaz-core" % "7.1.3"

y realizamos los siguientes imports:

import scalaz._, Scalaz._

Si cotilleamos un poco por la librería, podemos encontrarnos con la clase Monoid, o la clase Semigroup. En ellas estará definida la funcionalidad de la que podremos aprovecharnos.

En la clase Monoid está definido el método zero, que servirá para indicar cual es el elemento neutro. Además, en el trait MonoidLaw, está definida la regla fundamental que tiene que cumplir un elemento neutro.

Pero, ¿dónde está la información asociada a la propiedad asociativa?. Pues está en la clase Semigroup. Parece ser que los monoides son una especialización de los semigrupos. Estos últimos, son los encargados de la regla asociativa, mientras que los monoides añaden la regla del elemento neutro. De hecho, si nos vamos a la clase Semigroup, podemos encontrar el método append, el cual representará nuestra operación binaria |+|, y un poco más abajo podemos ver como está definida la propiedad asociativa.

Lo siguiente que debemos saber es que Scalaz se basa en una estructura de type classes. Es por ello que tendremos que implementar implicit objects, definiendo el comportamiento propio de nuestras estructuras respecto a las propiedades monádicas.

Después de esta escasa pero suficiente (o eso espero) información, vamos a ver como podemos aplicar todo este conocimiento con un ejemplo sencillo.

Creando nuestro propio monoide

Ahora, para acabar, vamos a crear nuestro propio monoide con Scalaz. Vamos a comenzar creando unos nuevos tipos de datos. Vamos a crear dos tipos de átomos: oxígeno e hidrógeno.

trait Atom
case object Oxygen extends Atom
case object Hydrogen extends Atom

Y para terminar, el tipo molécula. Dicho tipo tendrá un número determinado de átomos (que pueden ser de distintos tipos), y una estabilidad molecular.

case class Molecule(atoms: Map[Atom, Int], stability: Double)

jesse-pinkman-yeah-bitch-science

Queremos trabajar con nuestro tipo molécula como si fuera un monoide, para ello, utilizando las type classes de Scalaz, vamos a definir un implicit object definiendo el comportamiento monádico de la molécula (esto parece un trabalenguas):

implicit object MoleculeIsMonoid extends Monoid[Molecule] {

  def zero: Molecule = Molecule(Map(), 1)
  def append(f1: Molecule, f2: => Molecule): Molecule = f1.fusion(f2)

}

Hemos decidido que la molécula neutra sea aquella que no tiene átomos, y que su estabilidad es 1, la máxima estabilidad posible.

Además, hemos decidido que la suma de moléculas se delegue en una función llamada fusion. Vamos a ver como está definida:

case class Molecule(atoms: Map[Atom, Int], stability: Double) {

def fusion(other: Molecule): Molecule =
  Molecule(
    atoms = atoms |+| other.atoms,
    stability = stability * other.stability
  )
}

Como podemos observar, la fusión de dos moléculas consiste en sumar los átomos que las forman como si fueran monoides. Y es que resulta, que Scalaz nos proporciona funcionalidad para tratar la combinación de mapas como monoides. Además, vamos a combinar las estabilidades como si fueran probabilidades, es decir, multiplicándolas.

El método append también se puede utilizar mediante el símbolo |+|, justo como lo habíamos definido en un primer momento.

¡Y ya está! Ahora puedo fusionar moléculas aprovechándome de que son monoides, y de las operaciones que nos ofrece Scalaz con dichas abstracciones:

val m1 = Molecule(Map(Oxygen -> 1, Hydrogen -> 2), 0.2)
val m2 = Molecule(Map(Oxygen -> 1), 0.3)

m1 |+| m2
//Molecule(Map(Oxygen -> 2, Hydrogen -> 2), 0.06)

List(m1, m2, m2, m1).foldLeft(Molecule(Map(), 1))(_ |+| _)
//Molecule(Map(Oxygen -> 4, Hydrogen -> 4), 0.0036)

Some(m1) |+| Some(m2)
//Some(Molecule(Map(Oxygen -> 2, Hydrogen -> 2), 0.06))

46196561

Conclusión

Cuando llegues aquí espero que hayas perdido un poco de miedo a las palabras raras. Como hemos visto, las abstracciones algebraicas, son simplemente una manera de poner nombre a elementos que cumplen una serie de propiedades. Después, podremos beneficiarnos de esta abstracción para poder tratar varias operaciones distintas de la misma forma. Esta vez le ha tocado el turno a los monoides. Más adelante llegarán otros conceptos que ya te deberían de sonar, como las famosas mónadas. Ahora ya sabes, a fardar delante de tus amigos hablando de monoides 🙂

Anuncios

2 thoughts on “Teoría de Cate-movidas: Monoides

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