Recently I’ve been reading and thinking about type constructors in functional programming. Often these type constructors correspond to a basic construct from category theory: functors (at least). In programming, a functor is often described as something that “can be mapped over”, meaning that a type constructor `F[_]` is a functor if you can define a function `map(a: F[A])(f: A => B): F[B]`.

Another way to think about a functor `F[_]` is the following. A value of type `F[A]` is different from a value of type `A` because you cannot apply a function of type `A => B` to it. Instead, you lift the function to another function with the type `F[A] => F[B]`. This lifting is essentially the same thing as mapping, but focuses on the function rather than on the value the function is applied to. To emphasize this, we can swap the parameters of the function: `lift(f: A => B)(a: F[A]): F[B]`. When only applying the first parameter of `lift`, you obtain the lifted function of type `F[A] => F[B]`.

Now, the interesting aspect to think about is who controls the application of the function. As long as you have a plain function of type `A => B`, you can just apply it to a value of type `A` and get a `B`. However, if you lift the function into a functor and apply it to a `F[A]`, you transfer the responsibility for calling the original function to the functor. For example, if you lift a function into the `Option[_]` functor, it will be called once or not all; if you lift it into the `List[_]` functor, it might be called multiple times; and if you lift it into a functor like `Future[_]` or `Task[_]`, it might be called at a much later time.

This inversion of control is pretty much what the so-called “Hollywood Principle” is about: “don’t call us, we’ll call you”. In object-oriented programming, the Hollywood Principle is associated with using a framework (where you give up control) rather than a library (where your retain control). Thus, in some sense, functional type constructors are comparable to OO frameworks. I find this an interesting way to approach functors and their relatives.

Edit: Discussion on lobste.rs