# Diving into Scala Cats – Functors

### In this article, we'll dive into Cats to understand Functor type class.

Join the DZone community and get the full member experience.

Join For FreeIf 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.

In previous articles, we talked about Semigroups and Monoids, which are abstractions that let us combine values of the same type together.

In this post, we’ll take a look at **Functors**, which allow us to operate on values inside containers without having to know any of the implementation details of the containers themselves.

## What are Functors?

In terms of functional programming, a *Functor* is simply something that can be mapped over, or we can call it a *Mappable* instead.

It is basically* *an abstraction that allows us to

represent sequences of operations within a context such as Collections, Futures and Options.

Cats’ `Functor`

type class provides a base class for mappable types that allow us to write generic code for Futures, Options, Lists and more.* *

Standard Scala has no base type/trait to represent following generically:

`def calcBudget(orders: List[LineItem]) = orders.map(...)`

`def calcBudget(maybeOrder: Option[LineItem]) = maybeOrder.map(...)`

`def calcBudget(eventualOrder: Future[LineItem]) = eventualOrder.map(...)`

However using cats’ `Functor`

type class we can write a generic method like this:* *

`xxxxxxxxxx`

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

## Definition of a Functor

A `Functor `

is a type `F[A]`

with a map operation` (A => B) => F[B]`

:

`xxxxxxxxxx`

`package cats`

`trait Functor[F[_]] {`

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

`}`

It accepts the initial `F[A]`

as a parameter alongside the transformation function.

Let’s rewrite `calcBudget`

using `Functor`

:

`xxxxxxxxxx`

`import cats.Functor`

`case class LineItem(price: Double)`

`def calcBudget[F[_]](order: F[LineItem])(implicit ev: Functor[F]): F[LineItem] = {`

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

`}`

The `Functor[F].map(...)`

method is parameterized based on a type of `F[_]`

. Here `F[_]`

means any *type constructor* (type wrapping another type) that has a `map`

method e.g. `Option`

, `List`

, `Future`

etc.

The implicit parameter `ev: Functor[F]`

means that we must have a *type class implementation* in place that allows us to treat `F`

as a cats `Functor`

.

## Functor Laws

If we are creating our own Functors, then the `Functor `

must follow these laws.

*Identity*: If we pass an`identity`

function to the`Functor map`

method, then the`Functor`

must get back the original`Functor`

.*Composition*: If two functions execute sequentially like`(f andThen g`

)`(x)`

or`map(f).map(g)`

`g(f(x))`

.

## Functor Type Class and Instances

The Functor type class is `cats.Functor`

. Cats library provide us with inbuilt Functors and their implementation for predefined types like `Option`

, `List`

, `Future`

etc.

So far so good, let’s try to use type class implementation of `Functor`

for `List`

:

`xxxxxxxxxx`

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

Now let’s try to use type class implementation of `Functor`

for `Option`

:

`xxxxxxxxxx`

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

Now let’s try to use type class implementation of `Functor`

for `Future`

:

`xxxxxxxxxx`

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

Whenever we summon a `Functor `

for `Future`

, the compiler will

locate `futureFunctor `

by implicit resolution and recursively search for an`ExecutionContext `

at the call site. This is what the expansion might look

like:

`xxxxxxxxxx`

`// We write this:`

`Functor[Future]`

`// The compiler expands to this first:`

`Functor[Future](futureFunctor)`

`// And then to this:`

`Functor[Future](futureFunctor(executionContext))`

## Functor Syntax

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.

Cats allows us to do this by using the 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`

:

`xxxxxxxxxx`

`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 which can deal with any type and perform any mapping operation:

`xxxxxxxxxx`

`def withFunctor[A, B, F[_]](item: F[A], op: A => B)(implicit ev: 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)))`

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`

## Summary

In this article, we’ve looked at *Functors* provided by Scala Cats library. *Functors* represent sequencing behaviors. We talked about why do we need *Functors* and how can we define them. For a type class to be a *Functor* it must obey two *laws*: Firstly it should be possible to compose two *map* calls. Secondly mapping with the *identity* function should have no effect. We saw that we can write *Functor *type class implementation for all the *mappable *types present in Scala ecosystem *like* *Futures*, *Options*, *Lists, etc*. We’re not restricted to the types in the standard library, we can also add *map* method to our own types by using the concept of *syntax *or *extension* methods.

We’ll learn about more core concepts of Cats in our upcoming article.

Stay tuned!!!

## Learning Template

You can download the learning template *Scala Cats - Functors** *demonstrating the code implementations provided in this article.

## References

The best two Scala Cats resources I know are here:

- The Cats library is available at github.com/typelevel/cats
- The book,
*Advanced Scala with Cats*, is available at underscore.io/books/advanced-scala/

Published at DZone with permission of Mansi Babbar. See the original article here.

Opinions expressed by DZone contributors are their own.

Comments