Programación Funcional en JavaScript: La mónada Either

la-la-land-featured-image-gosling-stone.jpg

Descubrimos en el post anterior cómo concatenar funciones evitando la incómoda comprobación de ‘nulls’. Hicimos eso delegando el trabajo en una estructura de datos denominada mónada Maybe.

Explicamos las ventajas que tenía su uso y como esta estructura nos permite realizar aplicaciones seguras. Sin embargo, pudimos ver que era un estructura que no favorecía la detención de excepciones por no saberse donde se generaba dicho error.

Este problema será resuelto esta semana por una de las mónadas que vamos a presentar en esta serie: la mónada ‘Either’.

La mónada Either

La mónada `’Either’ es una evolución de la mónada ‘Maybe’ y se usa para representar una separación lógica entre dos valores que no pueden ocurrir al mismo. En nuestro caso más particular la obtención de un valor tras ejecutar una función  o una excepción.

Esta mónada vuelve a contar con 3 partes diferentes: La mónada en sí denominada ‘Either’ y dos tipos monádicos:

  • Left(a): Contiene un posible mensaje de error o una excepción.
  • Right(b): Contiene un valor obtenido del cómputo que hemos ejecutado.

Si nos ponemos a pensar, ‘Right’ se asemeja a ‘Just’ y ‘Left’ a ‘Nothing’, con la diferencia que esta última no guardaba un error, simplemente era una estructura vacía.

Las tres implementaciones involucradas en este patrón son las siguientes:

Mónada Either
class Either {
    constructor(value) { 
        this._value = value; 
    }
    static right(value) {
        return new Right(value);
    }

    static left(value) {
       return new Left(value);
    }

    static of(value) {
        return Either.right(value);
    }

    static fromNullable(value) {
       return value !== null ? Either.right(value) : Either.left(value);
    }
}
Tipo monádico Right
class Right extends Either {
    get value() {
        return this._value;
    }
    
    map(f) {
        return Either.fromNullable(f(this._value) || null);
    }

    orElse() {
        return this;
    }
    getOrElseThrow() {
        return this._value;   
    }
}
Tipo monádico Left
class Left extends Either {
    get value() {
        throw new TypeError('Can´t extract the value of the Left');
    }
    
    map() {
        return this;
    }
 
     orElse(f) { 
         return f(this._value); 
     }

     getOrElseThrow(a) { 
          return new Error(a); 
     } 
}

Pocos cambios con respecto a ‘Maybe’:

  • Ahora el constructor se encuentra en la estructura padre de la que heredan ambos. Como ambos guardan un valor, homogeneizamos el comportamiento.
  • Incluimos una función ‘orElse’ que nos permitirá mostrar el mensaje de error si fuese necesario en el caso de ‘Left’ y pasamos de ella si fuese un ‘Right’ el contenedor obtenido en la ejecución.
  • Hemos puesto una función ‘getOrElseThrow’ que nos permite empaquetar un mensaje por defecto como Error y en caso de que haya valor, obtener el valor.

Con esta estructura ya podemos manejar errores de una manera cómoda. Por ejemplo, volvamos a nuestro ya manido ejemplo de obtener un cliente de una base de datos. Podremos hacer algo tal que así:

const findClient = R.curry(function (db, clientId) {
    const client = find(clientId);
    
    if (client) {
        return Either.of(client);
    }

    return Either.left('Client not found in the db');
});

Y esto siendo un ejemplo académico, porque la propia mónada nos permite ser más implícitos:

const findClient = R.curry(function (db, clientId) {
    return Either.fromNullable(find(db, clientId))
});

Si por un casual, el cliente no existiese, podríamos hacer cosas de este estilo:

findClient('client-db', 1234).orElse(console.log);

Saliendo un error por consola de no haberse encontrado el cliente.

La mónada ‘Either’ nos puede ser muy útil en situaciones del código donde no tengamos control total y tengamos que gestionar excepciones. No nos quedará otra que hacer uso del ‘try-catch’ en estas situación, sin embargo, como veréis, la problemática ha cambiado radicalmente gracias a ‘Either’:

function decode(url) {
    try {
        return Either.of(decodeURIComponent(url));
    } catch (error) {
        return Either.left(error);
    }
}

Ahora ya no disparamos excepciones como en sistemas imperativos, simplemente envolvemos lo que ha pasado con la mónada para que las siguientes funciones puedan gestionar este problema.

Conclusión

Una vez que hemos conseguido crear un mejor envoltorio seguro para la aplicación de cómputos, nuestras aplicaciones son totalmente tolerante a fallos. Ninguna excepción se nos tiene porque escapar.

Ahora que hemos simulado una estructura ‘try-catch’ en un entorno funcional, ahora que ya hemos cubierto y asegurado la parte central de nuestras tuberías, es hora de que veamos cómo podemos protegernos de las entradas y salidas de nuestras tuberías, cómo podemos hacer que datos recibimos tengan una estructura funcional y se encuentre protegidos en envoltorios o contenedores.

La mónada que vendrá a echarnos una mano con esto se denomina mónada IO.

Aprovecharemos también ese post para hablar del encadenamiento y la composición de estructuras monádicas. Veremos cómo hacer que trabajen juntas y estudiaremos cómo todo este proceso será funcional y tolerante a fallos.

Nos leemos 🙂

Anteriores posts de Programación Funcional en JavaScript:

Introducción

  1. La Programación Funcional en JavaScript
  2. Programación Funcional en JavaScript: Los Objetos
  3. Programación Funcional en JavaScript: Las funciones

El control de flujo funcional

  1. Programación Funcional en JavaScript: Los métodos funcionales
  2. Programación Funcional en JavaScript: La recursividad

La modularidad funcional

  1. Programación Funcional en JavaScript: La aridad y las tuplas
  2. Programación Funcional en JavaScript: La currificación
  3. Programación Funcional en JavaScript: La composición
  4. Programación Funcional en JavaScript: Los combinadores

Patrones funcionales

  1. Programación Funcional en JavaScript: Los funtores
  2. Programación Funcional en JavaScript: La mónada Maybe
  3. Programación Funcional en JavaScript: La mónada Either
  4. Programación Funcional en JavaScript: La mónada IO
Anuncios

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