## 1. Overview

In this tutorial, we’ll take a look at *Functor* type class in *Cats*. The idea of *Functor* is “something that can be mapped over”, we’ll see what is actually mapped and how. In functional programming, ** Functors come into play when we have types or values wrapped inside contexts or containers.** We don’t have to know any of the implementation details of those contexts or containers themselves.

## 2. SBT Dependencies

To start, let’s add the Cats library to our dependencies :

libraryDependencies += "org.typelevel" %% "cats-core" % "2.2.0"

Here we’re using version 2.2.0 of the Cats library.

## 3. What is a Functor?

In terms of functional programming, **a Functor is a kind of container that can be mapped over by a function. **It is basically an abstraction that allows us to write generic code that can be used for

*Futures*,

*Options*,

*Lists*,

*Either*, or any other mappable type.

In simple terms, **any type that has a map function defined and preferably an “identity function” is a Functor.**

Standard library has no native base trait/type to represent this so we can write :

```
def calcBudget(orders: List[LineItem]) = orders.map(...)
def calcBudget(maybeOrder: Option[LineItem]) = maybeOrder.map(...)
def calcBudget(eventualOrder: Future[LineItem]) = eventualOrder.map(...)
```

But we can’t write it generically like this :

def calcBudget(order: Functor[LineItem]) = order.map(...)

## 4. The Cats Functor Type Class

However using cats’ *Functor *type class we can write a generic code that can be used for *Futures*, *Options*, *Lists*, *Either*, or any other mappable type.

But before that, let see definition of *Functor* type class. A *Functor *is defined as *F[A]* with a map operation *(A => B) => F[B]* :

package cats trait Functor[F[_]] {

def map[A, B](fa: F[A])(f: A => B): F[B]

}

Now let’s rewrite *calcBudget *using *Functor *:

import cats.Functor case class LineItem(price: Double) def calcBudget[F[_]](order: F[LineItem])(implicit functorEvidence: Functor[F]): F[LineItem] = {

Functor[F].map(order)(o => o.copy(price = o.price * 1.2))

}

Let’s decode this method signature.

The *calcBudget* method is parameterized based on a type of *F[_]*. Here *F[_]* means any mappable type e.g. *Option*, *List*, *Future*, etc. The parameter *order* itself is of type *F[LineItem]* i.e. any type wrapping a *LineItem*.

The implicit parameter *functorEvidence: Functor[F]* means that we must have a *type class implementation,* which allows us to treat *F* as a *Functor*.

In method body, we call *Functor[F].map()* i.e. we create a Functor for *F* using implicit evidence *functorEvidence* and call it’s *map* method.

## 5. Functor Laws

If we’re creating our own *Functors*, then those *Functors *have to respect some rules, called *Functor’s Laws* :

### 5.1. Identity Law

When a *Functor* is mapped over with identity function (the function returning its parameter unchanged), then we must get back the original *Functor *(the container and its content remain unchanged).

Functor[X].map(x => identity(x)) == Functor[X]

### 5.2. Composition Law

When a *Functor *mapped over the composition of two functions, then it should be same as mapping over one function after the other one.

Functor[X].map(f).map(g) == Functor[X].map(x => g(f(x))

## 6. Examples of Functors in Scala

In Scala, we are aware of *Functor’s* *map *function to work with effects. **Cats provide various type class implementations for Functors**, for predefined types like

*Lists*,

*Futures*,

*Options*,

*Either*, etc.

### 6.1. List as a Functor

Now, let’s see how *List* act as a *Functor* :

*List* is considered as a *Functor* as it has a *map* method. While iterating over *List* using its *map* method, we should think of it as transforming all of the values inside in one go, without changing the structure of the *List*.

We can implement the above concept using following example :

import cats.Functor object ListFunctor {

def transformList(list: List[Int]): List[Int] = {

Functor[List].map(list)(_ * 2)

}

} val list: List[Int] = List(1, 2, 3, 4, 5)

val transformedList = List(2, 4, 6, 8, 10)

assert(ListFunctor.transformList(list) == transformedList)

### 6.2. Option as a Functor

Now, let’s see how *Option* act as a *Functor* :

*Option *is also considered as a *Functor* as it also has a *map* method. When we map over an *Option*, we transform the contents but leave the *Some* or *None* context unchanged.

We can implement the above concept using following example :

import cats.Functor object OptionFunctor {

def transformOption(option: Option[Int]): Option[String] = {

Functor[Option].map(option)(_.toString)

}

} val option: Option[Int] = Some(10)

val transformedOption = Some("10")

assert(OptionFunctor.transformOption(option) == transformedOption)

### 6.3. Either as a Functor

Now, let’s see how *Either *act as a *Functor* :

*Either *is also considered as a *Functor* as it also has a *map* method. When we map over an *Either*, we transform the contents but leave the *Left *or *Right *context unchanged.

We can implement the above concept using following example :

import cats.Functor object EitherFunctor {

def transformEither(either: Either[Int, String]): Either[Int, Int] = {

Functor[Either].left.map(either)(_.size)

}

} val either: Either[Int, String] = Left("Baeldung")

val transformedEither = Left(8)

assert(EitherFunctor.transformedEither(either) == transformedEither)

### 6.4. Future as a Functor

Now, let’s see how *Future *act as a *Functor* :

*Future* is a *Functor* that sequences asynchronous computations by queueing them and applying them as their predecessors complete. The type signature of its *map* method has the same shape as the signatures above. However, the behavior is very different. **In case of Future, the wrapped computation may be ongoing, complete, or rejected.** If the

*Future*is complete, our mapping function can be called immediately. If not, some underlying thread pool queues the function call and comes back to it later. We don’t know when our functions will be called, but we do know what order they will be called in. In this way,

**.**

*Future*provides the same sequencing behavior seen in*List*,*Option*, and*Either*We can implement the above concept using following example :

import cats.Functor object FutureFunctor {

def transformFuture(future: Future[Int]): Future[Int] = {

Functor[Future].map(future)(_ + 1)

}

} val future: Future[Int] = Future{10}

val transformedFutureResult = 11

FutureFunctor.transformFuture(future).map(result => assert(result == transformedFutureResult))

## 7. Significance of Functors

By using Functors we’re not restricted to the types in the standard library, thus we can abstract over anything that is mappable.** We could define a map method to our own types **by using the concept of *syntax* or *extension* methods. This concept allows us to write *order.map(…)* instead of *Functor[F].map(order)(…)*. We can also drop the implicit evidence parameter by specifying that type *F[_]* is a *Functor *:

import cats.syntax.functor._ //for map def calcBudget[F[_]: Functor](order: F[LineItem]): F[LineItem] = {

order.map(o => o.copy(price = o.price * 1.2))

}

But we can also build a higher-order function that can deal with any type and perform any mapping operation :

def withFunctor[A, B, F[_]](item: F[A], op: A => B)(implicit functorEvidence: Functor[F]): F[_] = Functor[F].map(item)(op) val lineItemsList = List(LineItem(10.0), LineItem(20.0))

val result = FunctorSyntax.withFunctor(lineItemsList, calcBudget)

assert(result == List(LineItem(10.0), LineItem(20.0)))

In above example, *A*, *B* & *F* can be anything so long as the caller of the method :

- Supplies evidence that
*F*is a*Functor* - Knows how to map from
*A*to*B*

## 8. Summary

In this article, we’ve looked at *Functors* provided by Cats library of Scala. *Functor *is a kind of container that provides mapping function to represent sequencing behaviors. We talked about what is the need of *Functors* and how can we define them. Then we learned about two laws that a *Functor* has to respect. Then we saw that we can write *Functor *type class implementation for all the *mappable *types present in Scala ecosystem *like* *Futures*, *Options*, *Lists, Either, *etc. We’re not restricted to the types in the standard library. We can also define *map* method to our own types by using the concept of *syntax *or *extension* methods.

All the code implementations are available over on GitHub.

## Similar articles –

You can also checkout my other articles on *Scala Cats *series —

- Getting Started With Scala Cats
- Diving into Scala Cats — Semigroups
- Diving into Scala Cats — Monoids
- Diving into Scala Cats — Functors