13
votes

Meet the Applicative typeclass. It lies in the Control.Applicative module and it defines two methods, pure and <*>. It doesn't provide a default implementation for any of them, so we have to define them both if we want something to be an applicative functor.

I am trying to understand who is using pure function. I do use (<*>) function for which applicative functors are most useful for. But I am not sure who really uses pure.

I read something like pure (+3) <*> Just 10 but it can be written as Just (+3) <*> Just 10 too.

Above is just one confusion of too many I have. What is the true purpose of defining pure and when do I get to use it (or) who is already using it?

3
pure encapsulates a value into an arbitrary Applicative functor. Hence, pure 0 can mean any of: Just 0, [0], \_ -> 0, (mempty, 0), etc. Also note that return = pure.Dannyu NDos
Perfect, I could see how pure can be used to get a kind of polymorphism. Thank you :)Sumanth Kumar Mora

3 Answers

14
votes

<*> :: f (a -> b) -> f a -> f b, this operator accepts a function in the applicative type, as well as a value in the applicative type. The first argument of this operator can not thus be simply a function, but it has to be residing within an applicative.

The pure function solves problems that might occur here (e.g wanting to apply a function that is not residing in the applicative). It accepts a function that is not currently residing in the applicative, and lifts it into the applicative.pure :: a -> f a

(+3) :: Int -> Int, and Just 10 :: Maybe Int, you can not thus evaluate (+3) <*> Just 10 as the types do not work; the (+3) has to be promoted to a value in the Maybe applicative.

For Maybe a, the definition of pure is pure = Just, which is why you can write either pure (+3) or Just (+3)

--

I'll leave it to you to look into the <$> operator :-) Remember, every Applicative is a Functor.

6
votes

pure is like mempty for Monoid. mempty is neutral for mappend. pure is also neutral (in some sence) for <*>, it lifts some value to the functor without any effects or lifts with neutral effect.

This sentence can be formalized with four properties (copy/past from docs on Applicative):

pure id <*> v = v
pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
pure f <*> pure x = pure (f x)
u <*> pure y = pure ($ y) <*> u

What is the true purpose of defining pure and when do I get to use it (or) who is already using it?

Well, basically for writing more generalized code. For example:

when :: Applicative f => Bool -> f () -> f ()
when p s = if p then s else pure ()

sequenceA_ :: Applicative f => [f a] -> f ()
sequenceA_ = foldr (*>) (pure ())

traverse_ :: Applicative f => (a -> f b) -> [a] -> f ()
traverse_ f = foldr ((*>) . f) (pure ())

Also, sometime more simpler to use pure then implicitly wrap a value to a functor. For example, compare:

pure 3 ~ StateT (\s -> Identity (3, s))
4
votes

There are a few situations to use pure.

  1. As freestyle's answer illustrated, when you don't know what specific Applicative is being used.

  2. Also from freestyle, when its just more convenient to use pure.

In addition to just being simpler to write in some cases, it can make your code more robust. As I've develop software, my key data structures often evolve. Using pure instead of a specific constructor helps create spots of code that can remain unchanged during refactoring.

  1. When the implementation of the specific Applicative is unavailable.

Sometimes a library will not export constructors for their data types. Instead they rely on functions to build valid instances of the types. Making that type a member of Applicative is one way to do this. The IO Monad (Applicative) is another example of a type for which a constructor just isn't available. Instead, we are forced to use pure (aka return).