Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are Functors useful?

We know that any generic type F[_] withmap method, which complies to some laws, is a functor. For instance, List[_], Option[_], and F[A] = Env => A are functors. I am just wondering if this functor abstraction is meaningful.

How can I use the fact that they are functors ? Could you show an example of non-trivial computation, which would use the map and be actually useful ?

like image 525
Michael Avatar asked Jun 20 '16 18:06

Michael


3 Answers

One of the biggest benefits of concepts like functions is that there are generic constructions that allow you to build more complex types out of simpler functors, and guarantee that these complex types have certain properties. Functors understandably seem rather pointless when you consider them in isolation as you have done, but they become more and more useful the more such constructions you learn and master.

One of the simpler examples is that several ways of combining functors also yield a functor; e.g., if List[A] and Option[A] are functors, so are:

  • Composition of functors: List[Option[A]] and Option[List[A]]
  • Products of functors: (List[A], Option[A])
  • Sums of functors: Either[List[A], Option[A]]

I don't know enough to write this out in Scala, but in Haskell facts like these translate into generic code like these examples:

-- A generic type to represent the composition of any two functors
-- `f` and `g`.
newtype Compose f g a = Compose { getCompose :: f (g a) }

-- If `f` and `g` are functors, so is `Compose f g`.
instance (Functor f, Functor g) => Functor (Compose f g) where
  fmap f (Compose fga) = Compose (fmap (fmap f) fga)

This is a very simple example, but:

  • It's already useful as an analytical tool at least. A lot of data types that people write in practice, when you look at them through the lens of this example, turn out to be products, sums or compositions of simpler functors. So once you understand these constructions you can automatically "sense" when you write a complex type that it is a functor, and how to write its map() operation.
  • The more elaborate examples have the same flavor:
    • We have a generic construction that guarantees certain contracts when instantiated with a type that implements Functor;
    • When we add a Functor implementation to any a type, we gain the ability to use that type in that construction.

A more elaborate example is free monads (link has an extended Scala example), a generic interpreter construction that relies on user-supplied Functors to define the "instructions" for the language. Other links (and these are mostly straight from a Google search):

  • https://softwaremill.com/free-monads/
  • http://underscore.io/blog/posts/2015/04/14/free-monads-are-simple.html
like image 118
Luis Casillas Avatar answered Sep 25 '22 21:09

Luis Casillas


I don't know Scala, but in Haskell, the Functor class is essential to defining Van Laarhoven-style lenses:

type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s

These lenses are typically defined for specifically-related types s and a, but it's essential to their utility that they work with an arbitrary functor.

Functor is also important in its role as a superclass of Applicative and of Traversable. When working with these more powerful abstractions, it's often very useful to reach for the fmap method.

like image 42
dfeuer Avatar answered Sep 25 '22 21:09

dfeuer


Well, once you know something is a Functor, you don't just get map, you get all of the functions you can derive with it too

For example, it's possible to derive the function lift in a way that works for any functor.

Lift will "lift" a function from A => B to F[A] => F[B] for some Functor F[_] and is defined as

def lift[A, B](f: A => B): F[A] => F[B] = map(_)(f)

If you are using a library like cats or scalaz then you get these functions for free. The cats documentation has a few other examples you might be interested in

like image 35
Hamish Avatar answered Sep 23 '22 21:09

Hamish