# Explore “herding cats”: Functor

Functor extends Invariant.

``````trait Functor[F[_]] extends Invariant[F]
``````

That’s a little bit tricky once invariant functor is typically explained as mix of usual (covariant) and contravariant functors. Those functors are something like:

``````trait CovariantFunctor[A]:
def map[B](f: A => B): CovariantFunctor[B]

trait ContravariantFunctor[A]:
def contramap[B](f: B => A): ContravariantFunctor[B]
``````

With HKT precise definitions are going to be:

``````trait CovariantFunctor[F[_]]:
def map[A, B](fa: F[A])(f: A => B): F[B]

trait ContravariantFunctor[F[_]]:
def contramap[A, B](fa: F[A])(f: B => A): F[B]
``````

Let’s return back to the notion of Invariant. Cats Invariant doc and Softwaremill Invarian note provide nice examples. Nevertheless, I want to attempt to bring something extremely down-to-earth.

Let we have some thin wrapper:

``````trait EqWrapper[T]:
def eqv(valueToCompare: T): Boolean
def get: T
``````

String implementation:

``````class StringEqWrapper(private val value: String) extends EqWrapper[String] {
def eqv(valueToCompare: String): Boolean = valueToCompare == value
def get: String = value
}
``````

We can assume that in real world we define some non-trivial behaviour. It would be nice to have opportunity to derive new instances from old one using old ones as “back end”.

Let’s attempt to do it with usual `map`:

``````class StringEqWrapper(private val value: String) extends EqWrapper[String] { self =>
def eqv(valueToCompare: String): Boolean = valueToCompare == value
def get: String = value
def map[T](f: String => T): EqWrapper[T] = new EqWrapper[T] {
override def eqv(valueToCompare: T): Boolean = self.eqv("dummy") // I need T => String here to convert value to familiar strings
override def get: T = f(self.get) //map of basic covariant functor works well
}
}
``````

At that point we see that `String => T` helped to implement `get`. We just apply function to underlying string value and return result.

But we can’t compare `T` with `String`.

Contravariant approach leads to opposite result.

``````class StringEqWrapper2(private val value: String) extends EqWrapper[String] { self =>
def eqv(valueToCompare: String): Boolean = valueToCompare == value
def get: String = value
def map[T](f: T => String): EqWrapper[T] = new EqWrapper[T] {
override def eqv(valueToCompare: T): Boolean = self.eqv(f(valueToCompare)) // I know how to convert that T value to well-known String
override def get: T = null.asInstanceOf[T] //I'm in trouble, I have String state but no idea how to return T value
}
}
``````

We can derive implement `eqv(valueToCompare: T)` to compare `T` with internal `String` state.

But `get` require something to convert internal `String` state to `T`.

``````class StringEqWrapper(private val value: String) extends EqWrapper[String] { self =>
def eqv(valueToCompare: String): Boolean = valueToCompare == value
def get: String = value
def imap[T](f: String => T, g: T => String): EqWrapper[T] = new EqWrapper[T] {
override def eqv(value: T): Boolean = self.eqv(g(value))
override def get: T = f(self.get)
}
}
``````

Now we can derive new instance with `imap`:

``````val stringEqWrapper = new StringEqWrapper3("42")
val intEqWrapper: EqWrapper[Int] = stringEqWrapper.imap(_.toInt, _.toString)

intEqWrapper eqv 42 //true
``````

Typelevel Functor docs provides good description of API.

Explicitly I can denote that it is a right time to pay attention to type lambdas, there is also nice rockthejvm post about it.

``````import cats.Functor
val listFuntor: Functor[List] = Functor[List]
listFuntor.as(List(1, 2, 3), "a") //List(a, a, a)

val listOfOptionFunctor: Functor[[α] =>> List[Option[α]]] = listFuntor.compose[Option] //Functor[λ[α => F[G[α]]]] in Scala2
listOfOptionFunctor.map(List(Some(1), None))("N" + _) //val res0: List[Option[String]] = List(Some(N1), None)
``````

Functor examples

Tags:

Categories:

Updated: