¿Es Validated un Applicative?
Tags: kotlin, arrow, showdev
Published: 2021-11-19 08:41:09

Preguntas y respuestas sobre las [sesiones](https://dev.to/rogervinas/series/14723) *live coding* de [Arrow](https://arrow-kt.io/).

La siguiente pregunta fue realizada durante la [tercera sesión](https://dev.to/adevintaspain/kotlinarrow-gestion-de-errores-con-validated-pcm). Os dejamos también el enlace directo a la [discusión en Github](https://github.com/AdevintaSpain/wonderful-freshair-app/discussions/7) y el enlace del [vídeo en el momento de la pregunta](https://www.youtube.com/watch?v=989t4x2gMJQ&t=5532s).

## Pregunta
Hoy nos toca una pregunta cerrada: ¿es Validated un Applicative?. Intentaremos desarrollar un poco la respuesta.

## Respuesta
Durante la sesión no respondimos por varias razones: la primera es que intentamos guiar estas sesiones explicando el porqué y cómo introducir [Arrow](https://arrow-kt.io/) en nuestro código [Kotlin](https://kotlinlang.org/) en el back-end. Hemos preferido centrarnos en las características que nos ofrecen tipos cómo _Either_, _Validated_ o _NonEmptyList_ en nuestro trabajo diario con código [OOP](https://es.wikipedia.org/wiki/Programaci%C3%B3n_orientada_a_objetos) y cómo incorporarlos a nuestro código base, que en la teoría matemática formal que los sustenta, la [Teoría de categorías](https://es.wikipedia.org/wiki/Teor%C3%ADa_de_categor%C3%ADas). La segunda es que durante las primeras dos sesiones, no queríamos hablar de [FP](https://es.wikipedia.org/wiki/Programaci%C3%B3n_funcional). Nos lo reservamos para las siguientes sesiones.

De hecho, estas sesiones pretender simular un caso de uso sintético de migración iterativa, más o menos exportable a nuestro día a día, desde _OOP_ a _FP_ usando **Kotlin** y **Arrow**. Lo hacemos, no porqué creamos que un paradigma de programación sea mejor que el otro en términos absolutos, sino porqué pensamos que en el contexto del desarrollo de  aplicaciones en Internet escalables de ciertas dimensiones y cambio constante, la _FP_ puede ayudar mucho a entender el código y a aumentar su rendimiento de forma, creemos, más sencilla que la _OOP_.

Volviendo a la pregunta, ¿es [Validated](https://arrow-kt.io/docs/apidocs/arrow-core/arrow.core/-validated/) un [Applicative](https://en.wikipedia.org/wiki/Applicative_functor)? 

La única forma de demostrarlo es haciendo una verificación formal, comprobando que _Validated_ cumple con las leyes matemáticas cómo [Functor](https://en.wikipedia.org/wiki/Functor) así cómo también cumple con las leyes matemáticas de [Applicative Functor](https://en.wikipedia.org/wiki/Applicative_functor). 

Hemos creado un pequeño test [ValidatedAsApplicativeTest](https://github.com/AdevintaSpain/wonderful-freshair-app/blob/master/src/test/kotlin/com/wonderful/freshair/ValidatedAsApplicativeTest.kt) con [Kotest](https://kotest.io/) para comprobar estas propiedades. De todos modos, _Validated_ además de ser un _Functor_ y un _Applicative_, es también un _Type Constructor_, concretamente construye _Coproducts_ o _Sum types_ del tipo _Valid_ o _Invalid_ para pares de tipos concretos. Los test que hemos hecho utilizan  `Validated<Nothing, String?>` y `ValidatedNel<String?, String?>`. Ésta es una desventaja que tiene la programación en Kotlin con las matemáticas. Debo crear instancias concretas de tipos para poder utilizarlos en test y por tanto, estoy comprobando únicamente esas leyes para esos tipos concretos, y no para todos los tipos que _Validated_ puede construir.

* [Conservación de los morfismos de identidad.](https://github.com/AdevintaSpain/wonderful-freshair-app/blob/master/src/test/kotlin/com/wonderful/freshair/ValidatedAsApplicativeTest.kt#L25)
```kotlin
"Validated functor must preserve identity arrows" {
  checkAll(genNullableString) { a ->
    identity(a.valid()) shouldBe identity(a).valid()
    identity(a.invalid()) shouldBe identity(a).invalid()
  }
}
```
* [Conservación de la composición de morfismos.](https://github.com/AdevintaSpain/wonderful-freshair-app/blob/master/src/test/kotlin/com/wonderful/freshair/ValidatedAsApplicativeTest.kt#L32)
```kotlin
"Validated functor must preserve function composition" {
  checkAll(genNullableString) { a ->
    val f = { b: String? -> "PRE-APPENDED${b}" }
    val g = { b: String? -> "${b}POST-APPENDED" }
    g.compose(f)(a).valid() shouldBe a.valid().map(g.compose(f))
    g.compose(f)(a).invalid() shouldBe a.invalid().mapLeft(g.compose(f))
  }
}
```
* [Identidad.](https://github.com/AdevintaSpain/wonderful-freshair-app/blob/master/src/test/kotlin/com/wonderful/freshair/ValidatedAsApplicativeTest.kt#L41)
```kotlin
"Validated applicative must satisfy identity law" {
  checkAll(genValidated) { validated ->
    val validatedId = Validated.lift<NonEmptyList<String>, String?, String?>{ a -> identity(a) }
    validatedId(validated) shouldBe validated
  }
}
```
* [Homomorfismo.](https://github.com/AdevintaSpain/wonderful-freshair-app/blob/master/src/test/kotlin/com/wonderful/freshair/ValidatedAsApplicativeTest.kt#L48)
```kotlin
"Validated applicative must satisfy homomorphism law" {
  checkAll(genNullableString) { a ->
    val f = { b: String? -> "PRE-APPENDED${b}" }
    val validatedF = Validated.lift<Nothing, String?, String?>(f)
    validatedF(a.valid()) shouldBe f(a).valid()
  }
}
```
* [Intercambio.](https://github.com/AdevintaSpain/wonderful-freshair-app/blob/master/src/test/kotlin/com/wonderful/freshair/ValidatedAsApplicativeTest.kt#L56)
```kotlin
 "Validated applicative must satisfy interchange law" {
  checkAll(genNullableString) { a ->
    val f = { b: String? -> "PRE-APPENDED${b}" }
    val validatedF1 = Validated.lift<Nothing, String?, String?>(f)
    val validatedF2 = Validated.lift<Nothing, (String?) -> String?, String?> { f -> f(a) }
    validatedF1(a.valid()) shouldBe validatedF2(f.valid())
  }
}
```
* [Composición.](https://github.com/AdevintaSpain/wonderful-freshair-app/blob/master/src/test/kotlin/com/wonderful/freshair/ValidatedAsApplicativeTest.kt#L65)
```kotlin
"Validated applicative must satisfy composition law" {
  checkAll(genNullableString) { a ->
    val f = { b: String? -> "PRE-APPENDED${b}" }
    val g = { b: String? -> "${b}POST-APPENDED" }
    val validatedF1 = Validated.lift<Nothing, String?, String?>(f)
    val validatedF2 = Validated.lift<Nothing, String?, String?>(g)
    (validatedF2.compose(validatedF1))(a.valid()) shouldBe validatedF1(validatedF2(a.valid()))
  }
}
```
Hemos utilizado la función _lift_ de _Validated_ para comprobar estas leyes, inspirados en la definición formal de estas leyes en [Haskell](https://www.haskell.org/). Sin embargo, preguntando a la comunidad de [Arrow](https://arrow-kt.io/) nos comentaron que aunque son correctas, sería mas idiomático verificarlas usando la función _zip_ de _Validated_.  Es un ejercicio que queda pendiente.Y si queréis contribuir con ello haciendo una [PR a nuestro repo](https://github.com/AdevintaSpain/wonderful-freshair-app)  será más que bienvenida.

Encontrarás las verificaciones formales matemáticas de Functor y Applicative en [The Dao of Functional Programming](https://github.com/BartoszMilewski/Publications/blob/master/TheDaoOfFP/DaoFP.pdf) de @BartoszMilewski. Libro que te recomiendo si te quieres introducir en _Teoría de categorías_.

[![Ofertas Backend](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v6l1ob19ju6ol8ksv356.png)](https://careers.adevinta.es/ofertas/?search=backend&stc=aff-blog%20dev.to-%C2%BFEs%20Validated%20un%20Applicative%3F)