Learn You a Haskell for Great Good! - Miran Lipovaca [107]
instance Applicative ((->) r) where
pure x = (\_ -> x)
f <*> g = \x -> f x (g x)
When we wrap a value into an applicative value with pure, the result it yields must be that value. A minimal default context still yields that value as a result. That’s why in the function instance implementation, pure takes a value and creates a function that ignores its parameter and always returns that value. The type for pure specialized for the (->) r instance is pure :: a -> (r -> a).
ghci> (pure 3) "blah"
3
Because of currying, function application is left-associative, so we can omit the parentheses.
ghci> pure 3 "blah"
3
The instance implementation for <*> is a bit cryptic, so let’s just take a look at how to use functions as applicative functors in the applicative style:
ghci> :t (+) <$> (+3) <*> (*100)
(+) <$> (+3) <*> (*100) :: (Num a) => a -> a
ghci> (+) <$> (+3) <*> (*100) $ 5
508
Calling <*> with two applicative values results in an applicative value, so if we use it on two functions, we get back a function. So what goes on here? When we do (+) <$> (+3) <*> (*100), we’re making a function that will use + on the results of (+3) and (*100) and return that. With (+) <$> (+3) <*> (*100) $ 5, (+3) and (*100) are first applied to 5, resulting in 8 and 500. Then + is called with 8 and 500, resulting in 508.
The following code is similar:
ghci> (\x y z -> [x,y,z]) <$> (+3) <*> (*2) <*> (/2) $ 5
[8.0,10.0,2.5]
We create a function that will call the function \x y z -> [x,y,z] with the eventual results from (+3), (*2) and (/2). The 5 is fed to each of the three functions, and then \x y z -> [x, y, z] is called with those results.
Note
It’s not very important that you get how the (->) r instance for Applicative works, so don’t despair if you don’t understand this all right now. Try playing with the applicative style and functions to get some insight into using functions as applicatives.
Zip Lists
It turns out there are actually more ways for lists to be applicative functors. We’ve already covered one way: calling <*> with a list of functions and a list of values, which results in a list containing all the possible combinations of applying functions from the left list to the values in the right list.
For example, if we write [(+3),(*2)] <*> [1,2], (+3) will be applied to both 1 and 2, and (*2) will also be applied to both 1 and 2, resulting in a list that has four elements: [4,5,2,4]. However, [(+3),(*2)] <*> [1,2] could also work in such a way that the first function in the left list is applied to the first value in the right one, the second function is applied to the second value, and so on. That would result in a list with two values: [4,4]. You could look at it as [1 + 3, 2 * 2].
An instance of Applicative that we haven’t encountered yet is ZipList, and it lives in Control.Applicative.
Because one type can’t have two instances for the same type class, the ZipList a type was introduced, which has one constructor (ZipList) with just one field (a list). Here’s the instance:
instance Applicative ZipList where
pure x = ZipList (repeat x)
ZipList fs <*> ZipList xs = ZipList (zipWith (\f x -> f x) fs xs)
<*> applies the first function to the first value, the second function to the second value, and so on. This is done with zipWith (\f x -> f x) fs xs. Because of how zipWith works, the resulting list will be as long as the shorter of the two lists.
pure is also interesting here. It takes a value and puts it in a list that just has that value repeating indefinitely. pure "haha" results in ZipList (["haha", "haha","haha".... This might be a bit confusing, since you’ve learned that pure should put a value in a minimal context that still yields that value. And you might be thinking that an infinite list of something is hardly minimal. But it makes sense with zip lists, because it must produce the value on every position. This also satisfies the law that pure f <*> xs should equal fmap f xs. If pure 3 just returned ZipList [3], pure (*2) <*> ZipList [1,5,10] would result in ZipList [2], because