HOME - BLOG POSTS - TYPELEVEL CATS

# What is a Functor?

- 7 minutes read - 1378 wordsYou’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

Cats’ *Functor* type class allow us to write generic code that can be used for Futures, Options, Lists and more

You can find complete examples of the concepts discussed on my blog in my Github repo In particular, check out the Functors example

## 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 i.e. List, Option, Future etc. ^{1} 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 write:

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

but 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 `F`

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 create a Functor for `F`

using 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*.
Cats 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 `Som`

e 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.

`cats.syntax.option._`

then write something like `val maybeLineItem = LineItem(10.0).some`

.The

`.some`

call is equivalent to `Some(LineItem(10.0))`

but it tells the compiler to treat the `Some`

as an `Option`

## Why is all this significant?

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 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. So why is this significant?

Well firstly it *may* be useful to have some generic code that can handle Options, Futures, Lists etc but the real power comes
when we need to test it. Take our original withVat function that accepts Futures:

```
def withVat(eventualOrder: Future[LineItem]): Future[LineItem] = ???
```

To test this we need to create an instance of a Future and then block/await for the result or otherwise use something
like Scalatest’s async specs. It’s a bit nasty. By accepting a generic `Functor`

we can pass an option in the test:

```
def withVat[F[_]](order: F[LineItem])(implicit ev: Functor[F]): F[LineItem] = ???
...
withVat(LineItem(10.0).some) shouldBe LineItem(12.0).some
```

cats also includes a helper Type called `Id`

which lets us pass “raw” types in e.g.

```
import cats.Id
...
withVat(LineItem(10.0): Id[LineItem]) shouldBe LineItem(12.0)
```

It’s just another compiler trick with tells the compiler to treat `A`

as `F[A]`

## Simplifying the code

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 map from A to 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(applyVat))
```

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)(applyVat)
```

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(applyVat)
```

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(applyVat)
```

### What next?

I’ve covered `map`

now it’s time to cover `flatMap`

. To do so you need to read about Monads …

#### Laws

Firstly it should be possible to compose two map calls. Secondly mapping with the *identity* function should have no
effect. You can read more on the cats website