How are functors useful?

We know that any generic type F[_] with a map method that matches some laws is a functor. For example, List[_] , Option[_] and F[A] = Env => A are functors. I'm just wondering if this functor abstraction makes sense.

How can I use the fact that they are functors? Could you give an example of a nontrivial calculation that would use map and be really useful?

+5
source share
3 answers

One of the biggest advantages of concepts such as functions is the presence of common constructs that allow you to create more complex types from simpler functors and ensure that these complex types have certain properties. The functors understandable seem rather pointless when you consider them in isolation, as you did, but they become more and more useful, the more such constructions you learn and master.

One simple example is that several ways to combine functors also give a functor; for example, if List[A] and Option[A] are functors, that is:

  • The composition of the functors: List[Option[A]] and Option[List[A]]
  • Functor Products: (List[A], Option[A])
  • Sum of Functors: Either[List[A], Option[A]]

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

 -- A generic type to represent the composition of any two functors -- `f` and `g`. newtype Compose fga = Compose { getCompose :: f (ga) } -- If `f` and `g` are functors, so is `Compose fg`. instance (Functor f, Functor g) => Functor (Compose fg) where fmap f (Compose fga) = Compose (fmap (fmap f) fga) 

This is a very simple example, but:

  • It is already useful, at least as an analytical tool. Many types of data that people write in practice when you look at them through the lens of this example turn out to be products, amounts, or compositions of simpler functors. Therefore, when you understand these constructions, you can automatically “feel” when you write a complex type, which is a functor, and how to write its map() operation.
  • More complex examples have the same taste:
    • We have a general construction that guarantees certain contracts when creating an instance with a type that implements Functor ;
    • When we add a Functor implementation to any type, we get the opportunity to use this type in this construct.

A more complex example is free monads (the link has an extended Scala example), a general interpreter construct that relies on a custom Functor to define “instructions” for the language. Other links (and this is mostly straight from Google search):

+8
source

I don’t know Scala, but in Haskell, the Functor class is needed to define Van Laarchoven-style lenses :

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

These lenses are usually defined for specifically related types s and a , but for their usefulness it is important that they work with an arbitrary functor.

Functor also plays an important role as the superclass Applicative and Traversable . When working with these more powerful abstractions, it is often very useful to use the fmap method.

+6
source

Well, when you know that something is Functor, you do not just get a map , you get all the functions that you can get with it too

For example, you can get the lift function in such a way that it works for any functor.

The rise will “raise” the 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 use a library, such as cats or scalaz, then you get these functions for free. cat documentation contains several other examples that may interest you

+1
source

All Articles