Translate

domingo, 1 de mayo de 2022

Funtores en Cats parte 8

Vimos una instancia de functor para Function1. 

import cats.Functor

import cats.instances.function._ // for Functor

import cats.syntax.functor._

 // for map

val func1 = (x: Int)  => x.toDouble

val func2 = (y: Double) => y * 2

val func3 = func1.map(func2)

// func3: Int => Double = scala.Function1$$Lambda$7919/0


Function1 tiene dos parámetros de tipo (el argumento de la función y el tipo de resultado):

trait Function1[-A, +B] {
  def apply(arg: A): B
}

Sin embargo, Functor acepta un constructor de tipos con un parámetro:

trait Functor[F[_]] {
  def map[A, B](fa: F[A])(func: A => B): F[B]
}

El compilador tiene que corregir uno de los dos parámetros de Function1 para crear un constructor de tipos del tipo correcto para pasar a Functor. Tiene dos opciones a elegir:

type F[A] = Int => A
type F[A] = A => Double

Sabemos que la primera de ellas es la elección correcta. Sin embargo, el compilador no entiende lo que significa el código. En cambio, se basa en una regla simple, implementando lo que se llama "unificación parcial".

La unificación parcial en el compilador de Scala funciona fijando los parámetros de tipo de izquierda a derecha. En el ejemplo anterior, el compilador corrige Int en Int => Double y busca un Functor para funciones de tipo Int => ?:

type F[A] = Int => A
val functor = Functor[F]

Esta eliminación de izquierda a derecha funciona para una amplia variedad de escenarios comunes, incluidos Functors para tipos como Function1 y Either:

val either: Either[String, Int] = Right(123)
// either: Either[String, Int] = Right(123)
either.map(_ + 1)
// res0: Either[String, Int] = Right(124)