Right now I'm learning Haskell, a functional programming language. In my last few Haskell articles I've discussed basic aspects of the language. Now I've begun digging into advanced functional programming concepts. This article discusses functors, a generic way to map functions over objects.

A common pattern in programming is looping through a collection of values and applying a transformation to each. For example, a programmer might loop through a list of integers and increment each value. The imperative approach to this transformation sets up a for loop and iterates over each list index. The functional approach uses the `map`

higher-order function. `map`

accepts two arguments - a collection to iterate over and a function. The function is applied to each item in the collection.

Haskell has a `map`

function defined in the GHC Prelude module^{1}. It accepts a list and a function as arguments.

With the `map`

function, list items can be transformed. A basic example is incrementing each item in the list.

Haskell's `map`

function is useful, however its restricted to just a list data structure. The concept of applying a function across all items in a data structure can be generalized even more than the `map`

function. This is where functors come into play.

Functor

In Haskell (and functional programming in general), a functor provides the ability to map a function across all the items in a data structure or object^{2}. Functors in Haskell are defined by a `Functor`

type class. Types that are instances of `Functor`

implement a function called `fmap`

, which provides mapping functionality.

The `Functor`

type class definition is simple:

`fmap`

is a curried function that takes in another function [`(a -> b)`

] and a value whose type is an instance of `Functor`

[`f a`

] as arguments. `fmap`

passes `f a`

to the function `(a -> b)`

, resulting in `b`

.

The most basic functor instance is for the list type^{3}.

For lists, `fmap`

is implemented the same as `map`

. Therefore, it behaves as expected.

The great thing about functors is any parameterized type in Haskell can be made an instance of `Functor`

. For example, the `Maybe`

type which defines a potentially non-existant value can become a functor.

Custom types can also become functors. For example, my custom `Distance`

type is easily made an instance of `Functor`

.

`Distance`

is a valid functor instance because its data definition is parameterized and it has a type constructor. You can think of `Distance`

as a container type, since it holds a value such as a floating point number. Lists and the `Maybe`

type have similar structures. Types without a parameterized data definition are not valid functors because they don't contain another type^{4}.

Functors are useful for mapping functions across all items contained in an object. They become even more useful in regards to Applicatives and Monads, which I will discuss in upcoming articles.

For now, one last useful functor implementation is a generic function for all instances of `Functor`

to utilize. With the help of a `Functor`

class constant, a function is easily created to increment the items in any `Functor`

instance^{5}.

Any type that is an instance of `Functor`

can utilize the `inc`

function! This is a really powerful design pattern for function reuse.

The concept of functors isn't limited to Haskell or functional programming. In Java, the `Functor`

type class is represented as an interface^{6}.

Classes can implement the `Functor`

interface. This is comparable to creating an instance of the `Functor`

type class in Haskell. The following class creates a list that is also a functor.

Class `FList`

has a concrete implementation of `fmap()`

as required by the `Functor`

interface. For the sake of another example, the following class defines a functor for a pair of values.

The following code confirms that the functors behave as expected when invoking `fmap()`

.

For completeness, here is the generic `inc()`

function for functors in Java.

The same functor pattern works in many different languages!

Working with a functional programming language forces the brain to think about common problems differently. While initially difficult to reason about, functors simply provide a mechanism for mapping a function across different items. Functors also promote the creation of generic code which works for many different types. In my next article I'll build on this knowledge and explore applicatives. All the code from this article is available on GitHub.