Functor

A functor is a function that can be applied to a value. This turns out to be very useful. If you start with the number 1 and apply a function to it, for example, + 2 you arrive at the answer 3. Simple enough. But a functor has one important twist.

For example, if you have a domain object, such as a House and you want to apply a function to a value in the house, say a specific room, then House needs to have a method on its class that takes a function as an argument. That function would be used by House to apply it to the room to produce an output. The output stays in the house. For example, perhaps your functions paints the room. The room is still there and the original color is still there. But now there is a new color that covers the room.

A functor is a design pattern that applies a function to a value inside of a context like a House. There are a number of fancy rules that go along with this key idea. In scala, the map operation on class A means that class A is a functor assuming it obeys the other rules that are not detailed here. If you use the example of a list, a functor would allow you to apply a fuction to each element of a list and return a list where each element has been replaced by the function's output for that element.

That's it. In the programmer's world, a functor is usually expressed as a class that has a map function although there are other properties that must also be true.

scala> List[Int](1,2,3).map{ x:Int => x + 1}
List[Int](1,2,3).map{ x:Int => x + 1}
res23: List[Int] = List(2, 3, 4)

Once again, a list is a good way to play around and understand the concepts. A functor has a bit of strange syntax. To use a scalaz functor, you need to specify a type that takes a type. A scala List takes a type parameter so we can use List as the type parameter to the Functor smart constructor. Since the smart constructor does not take any arguments, you just write Functor[List] to create an instance. Once you have an instance you can use it directly.

scala> val f = Functor[List]
val f = Functor[List]
f: scalaz.Functor[List] = scalaz.std.ListInstances$$anon$1@1f8d2783

scala> f.map(List(1,2,3))(_+1)
f.map(List(1,2,3))(_+1)
res29: List[Int] = List(2, 3, 4)

This last example also showed that a Functor allows the application of a function in a context. The function was +1 and the context was the list. You can immediately see that a scala Future is a Functor because it allows you to apply a function to the Future's context. A scala Future's context is that of a value that is not yet available.

If we try to use this functor with something other than a list, say a scala Sequence then we get an error:

scala> f.map(Seq(1,2,3))(_+1)
f.map(Seq(1,2,3))(_+1)
<console>:33: error: type mismatch;
 found   : Seq[Int]
 required: List[?]
              f.map(Seq(1,2,3))(_+1)

A Functor can adapt to the types that you are using. Here's the same Functor instance but applied to Strings in the List "context."

scala> f.map(List("a","b"))(_ + "!")
f.map(List("a","b"))(_ + "!")
res34: List[String] = List(a!, b!)

There is alot more deep thoughts about functors but we will skip them.

Last updated