# Fun with Functors using Cats and Scala

You're probably familiar with the `map`

method in the Scala standard library. Collections, Futures and Options all have a map method but unfortunately there's no base class for *mappable* types, making it hard to write generic code

**TL;DR**Cats includes the

`Functor`

type class with implementations for Futures, Options, Lists etc. It essentially gives us the base class/trait that's missing in the standard library
## What is a type class?

If you're new to the concept of type classes I suggest you read my other article explaining them. The Cats library makes extensive use of type classes and a basic understanding is a prerequisite for this article

## Cats

Cats is a functional programming library which supports many advanced functional programming paradigms borrowed from languages such as Haskell. However you don't need a detailed understanding of category theory or functional programming to get value from Cats. In my own experience most people (myself included) benefit mostly from the more simple abstractions.

Cats defines type classes for various functional concepts along with implementations for common types. Of course, being type classes you can write your own implementations if a particular type is not supported "out of the box". Today we'll be looking at one of the most basic type classes - the Functor

Getting started with cats is pretty simple. At the time of writing the latest stable release is 1.0.1 and you can add it to your SBT build as usual:

```
libraryDependencies += "org.typelevel" %% "cats-core" % "1.0.1"
```

## What is a Functor?

In simple terms any *type constructor* (type wrapping another type) that has a `map`

method can be thought of as a Functor ^{[1]} i.e. List, Option, Future etc. The problem is that although we know List, Option and Future all have a map method the standard library has no base type/trait to represent this so we can't write:

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

## The Cats Functor type class

However using Cats' Functor type class we can write such a method:

```
import cats.Functor
case class LineItem(price: Double)
def withVat[F[_]](order: F[LineItem])(implicit ev: Functor[F]): F[LineItem] = {
Functor[F].map(order)(o => o.copy(price = o.price * 1.2))
}
```

Let's decode the method signature. The method is parameterised based on a type of `F[_]`

. This means any *type constructor* e.g. `Option, List, Future`

etc. At this stage we haven't specified anything about the type needing a `map`

method. The parameter itself is of type `F[LineItem]`

i.e. any type wrapping a `LineItem`

. Finally we have the implicit parameter `ev: Functor[F]`

which means we must have a type class implementation in place which allows us to treat F as a Cats Functor.

In the method body we call `Functor[F].map(...)`

i.e. we convert the order to a Functor based on the implicit "evidence" and call it's `map`

method. Our method should now compile but if we try to call it we'll run into a problem:

```
val lineItems = List(LineItem(10.0), LineItem(20.0))
withVat(lineItems).foreach(println)
Error:(15, 12) could not find implicit value for parameter ev: cats.Functor[List]
```

The compiler is telling us that we need to supply the evidence that `List`

is a `cats.Functor`

i.e. we need a type class implementation for `List`

. The Cats library includes such an implementation already so we can just use this:

```
import cats.Functor
import cats.instances.list._
def withVat[F[_]](...)
val lineItems = List(LineItem(10.0), LineItem(20.0))
withVat(lineItems).foreach(println)
```

So far so good, lets try to use an Option instead of a List. Again we'll need to pull in the type class implementation for Option:

```
import cats.Functor
import cats.instances.list._
import cats.instances.option._
val maybeLineItem = Some(LineItem(10.0))
withVat(maybeLineItem).foreach(println)
Error:(16, 12) could not find implicit value for parameter ev: cats.Functor[Some]
```

Hmmm, seems it didn't work. What went wrong? Actually we've run into an issue of *variance*. Cat's includes an implementation for `Option`

but we're passing `Some`

. We might expect that `Functor[Some]`

would be treated as `Functor[Option]`

(known as Covariance) but in fact Cats is generally invariant of types i.e. it wants an Option and only an Option, a Some or None won't do. We need to tell the compiler to treat our Some as an Option:

```
val maybeLineItem: Option[LineItem] = Some(LineItem(10.0))
withVat(maybeLineItem).foreach(println)
```

As you work with Cats you'll see this is a common theme so remember this compiler trick - you'll need it again for sure.

## Summary

By using the Functor type class we can abstract over anything that can be mapped. We're not restricted to the types in the standard library, we could add a `map`

^{[1:1]} method to our own types. So long as we write a Functor type class implementation for it we would pass it to our `withVat`

function above.

## What next?

Cats also introduces a concept of *syntax* or extension methods. This concept is implemented using implicit classes and allows us to write `order.map(...)`

instead of `Functor[F].map(order)(...)`

. We can also drop the implicit parameter by specifying that type F[_] is a Functor

```
...
import cats.syntax.functor._
def withVat[F[_]: Functor](order: F[LineItem]): F[LineItem] = {
order.map(o => o.copy(price = o.price * 1.2))
}
```

withVat adds VAT of 20% to `LineItems`

but we can build a higher order function which can deal with any type:

```
def withFunctor[A, B, F[_]: Functor](order: F[A])(op: A => B): F[_] = order.map(op)
val lineItems = List(LineItem(10.0), LineItem(20.0))
withFunctor(lineItems)(_.price * 1.2).foreach(println)
```

Of course this is a contrived example as `withFunctor`

adds no value over a simple inline call but it illustrates the point that A, B & F can be anything so long as the caller of the method:

- Supplies evidence that F is a Functor (an implementation)
- Knows how to handle A and B

### A Different view

All the examples I have given so far assume we want to write generic methods capable of handling Lists, Options, Futures etc and this is certainly a common use case for Functors. However we can also use functors inline in our code and this is especially useful when *composing* them. A common pattern we often see is something like:

```
val order: Future[Option[Order]] = fetchOrder(...)
order.map(_.map(calculateTotalPrice))
```

The nested map call is messy but as Cats includes Functor implementations for both Future and Option we can compose them:

```
import cats.Functor
import cats.instances.future._
import cats.instances.option._
...
Functor[Future].compose[Option].map(order)(calculateTotalPrice)
```

We can cut down the boilerplate by writing our own implicit class which adds a `nestedMap`

method to all nested Functors

```
implicit class RichFunctor[A, F[_]: Functor, G[_]: Functor](underlying: F[G[A]]) {
def nestedMap[B](op: A => B): F[G[B]] = Functor[F].compose[G].map(underlying)(op)
}
val order: Future[Option[Order]] = fetchOrder(...)
// use the new implicit method we defined above
order.nestedMap(calculateTotalPrice)
```

This will work for `Future[Option[A]]`

but it will also work for any combination of type constructors so long as we have the Functor type class implementations in scope:

```
...
import cats.instances.future._
import cats.instances.list._
val orders: Future[List[Order]] = fetchOrder(...)
orders.nestedMap(calculateTotalPrice)
```