# Lecture 10: Applicative functors (part 1) ## Motivation Let's suppose that we have the following `Employee` type with a single constructor: type Name = String data Employee = Employee { name :: Name, phone :: String } deriving Show The constructor for `Employee` is going to be a function with the following signature: Employee :: Name -> String -> Employee However, we might want to use this constructor in contexts where we don't know all fields, like in forms with optionally compilable parts. In that case, we can write a new function that turns the `Employee` constructor into something that returns a `Just Employee` only when both its fields have values, or `Nothing` otherwise. maybeEmployee :: (Name -> String -> Employee) -> (Maybe Name -> Maybe String -> Maybe Employee) What if we need to extract the fields of an `Employee` object from somewhere else, like a very large data structure or a remote database? extractedEmployee :: (Name -> String -> Employee) -> ((e -> Name) -> (e -> String) -> (e -> Employee)) We can write this function, too! As it turns out, there is only one way to write it. ## Generalizing If we extract the common parts of this pattern and make it generic to any type, we should end up with something like this: (a -> b -> c) -> (f a -> f b -> f c) This type looks familiar. In fact, it's just the type of `fmap` from the `Functor` class with an extra argument in the two functions! It would be nice if only we could write this new function, which we're going to call `fmap2`, in terms of `fmap`. We might think this is possible, considering that Haskell allows us to partially apply functions. However, despite our best effort, we actually cannot write `fmap2` in terms of `fmap`. The reason is that, by applying `fmap` to the arguments below one by one, we end up with the type below, which is far from our desired `fmap2`. h :: a -> (b -> c) fa :: f a fb :: f b fmap h fa :: f (b -> c) Our applied version of `fmap` lets us apply functions to values in a Functor context. However, we need our functions to be in the Functor context as well! The kind of Functor we need are called **applicative functors**, defined as follows and available in the standard library as `Control.Applicative`. class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b `(<*>)` is pronounced "ap" or "apply" and represents our "contextual application". `pure`, on the other hand, "injects" a value of a type into a container. An interesting aspect of `pure` is that, while our `fmap2` is `fmap` with one more argument, `pure` is `fmap` with one *less* argument. Notice that, since Applicative requires its instances to be instances of Functor as well, we can always use `fmap` with instances of Applicative. Using `(<*>)` we can now implement `fmap2`, which is also available in the standard library as `liftA2`. The standard library also defines a synonym for `fmap`, `(<$>)`, available in `Control.Applicative`. As a result, `liftA2` is simply written as: liftA2 :: Applicative f => (a -> b -> c -> f a -> f b -> f c liftA2 h fa fb = h <$> fa <*> fb We can write `liftA3` similarly, with the same operators: liftA3 :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d liftA3 h fa fb fc = ((h <$> fa) <*> fb) <*> fc Note how going from `fmap` to `liftA2` required to introduce Applicative, while going from `liftA2` to `liftA3` didn't require further generalization. On the other hand, `pure` is useful when we need to apply a function to its arguments in the context of some functor `f`, with one or more arguments not being in `f`. Those arguments are often called "pure". By using `pure`, we can lift the arguments not in `f` before applying. ## Applicative laws An interesting law is the following: f `fmap` x === pure f <*> x In other words, applying a function `f` to a container `x` gives the same result as first injecting the function into the container and then applying it to `x` wih `<*>`. ## Applicative examples An instance of `Applicative Maybe` could be written like this: instance Applicative Maybe where pure = Just Nothing <*> _ = Nothing _ <*> Nothing = Nothing Just f <*> Just x = Just (f x)