Cogs and Levers A blog full of technical stuff

Functors in Scala

Scala’s type is very rich; even where constructs aren’t well defined you can easily piece together anything that you need. In today’s article, I’ll take you through some different functor types as well as a small primer on variance.

Variance

Type variance is what we use to describe sub-class relationships in a class hierarchy. In scala we use the following notations to denote variances:

  Description Notation
covariant C[T'] is a subclass of C[T] [+T]
contravariant C[T] is a subclass of C[T'] [-T]
invariant C[T] and C[T'] are not related [T]

Functors

Covariant functors are what provide map or fmap:

trait Functor[F[_]] {
  def fmap[A, B](f: A => B): F[A] => F[B]
}

Contravariant functors provide contramap:

trait Contravariant[F[_]] {
  def contramap[A, B](f: B => A): F[A] => F[B]
}

Exponential functors are what provide xmap:

trait Exponential[F[_]] {
  def xmap[A, B](f: (A => B, B => A)): F[A] => F[B]
}

Applicative functors are what provide apply and <*>:

trait Applicative[F[_]] {
  def apply[A, B](f: F[A => B]): F[A] => F[B]
}

Monads provide bind, flatMap or =<<:

trait Monad[F[_]] {
  def flatMap[A, B](f: A => F[B]): F[A] => F[B]
}

Comonads provide extend, coflatMap and <<=:

trait Comonad[F[_]] {
  def coflatMap[A, B](f: F[A] => B): F[A] => F[B]
}