Veamos la implementación de funtores contravariantes e invariantes en Cats, proporcionados por las clases de tipos cats.Contravariant y cats.Invariant.
trait Contravariant[F[_]] {
def contramap[A, B](fa: F[A])(f: B => A): F[B]
}
trait Invariant[F[_]] {
def imap[A, B](fa: F[A])(f: A => B)(g: B => A): F[B]
}
Podemos invocar instancias de Contravariant utilizando el método Contravariant.apply. Cats proporciona instancias para tipos de datos que consumen parámetros, incluidos Eq, Show y Function1.
Veamos un ejemplo:
import cats.Contravariant
import cats.Show
import cats.instances.string._
val showString = Show[String]
val showSymbol = Contravariant[Show].contramap(showString)((sym: Symbol) => s"'${sym.name}")
showSymbol.show(Symbol("dave"))
// res1: String = "'dave"
Más convenientemente, podemos usar cats.syntax.contravariant, que proporciona un método de extensión de contramap:
import cats.syntax.contravariant._ // for contramap
showString.contramap[Symbol](sym => s"'${sym.name}").show(Symbol("dave"))
// res2: String = "'dave"