Functors in Scala
05 Feb 2017Scala’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]
}