Related
So I'm trying to learn about monads, functors and applicatives. I've created the following renamed mirror match of Maybe called Sometimes. (I did this to learn about these things)
data Sometimes a = Nope | Thing a deriving Show
instance Monad Sometimes where
(Thing x) >>= f = f x
Nope >>= f = Nope
return = Thing
instance Applicative Sometimes where
pure = Thing
Nope <*> _ = Nope
(Thing g) <*> mx = fmap g mx
instance Functor Sometimes where
fmap _ Nope = Nope
fmap g (Thing x) = Thing (g x)
So when I do the following it works:
pure (1+) <*> (Thing 1)
> Thing 2
pure (+) <*> (Thing 1) <*> (Thing 1)
> Thing 2
But if I try three additions it doesn't work:
pure (+) <*> (Thing 1) <*> (pure 1) <*> (pure 1)
<interactive>:108:1: error:
• Non type-variable argument in the constraint: Num (a -> b)
(Use FlexibleContexts to permit this)
• When checking the inferred type
it :: forall a b. (Num (a -> b), Num a) => Sometimes b
Why doesn't this work? I would expect the first two to be applied and then the third to be applied to the result of the first two. My book talks about how implementing fmap0, fmap1, fmap2... is inefficient and as such
... for functions with any desired number of arguments can be constructed in terms of two basic functions with the following types:
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
And states further on:
A typical use of pure and <*> has the following form:
pure g <*> x1 <*> x2 <*> ... <*> xn
As such I'm expecting it to work but I'm clearly missing something in my definitions/usage of the Applicative.
I'm using the book Programming in Haskell SE by Graham Hutton
The reason this does not work is because (+) sums two numbers, not three.
You can make a function that sums three numbers, for example with:
pure (\x y z -> x+y+z) <*> (Thing 1) <*> (pure 1) <*> (pure 1)
this then gives us:
Prelude> pure (\x y z -> x+y+z) <*> (Thing 1) <*> (pure 1) <*> (pure 1)
Thing 3
Why doesn't this work? I would expect the first two to be applied and then the third to be applied to the result of the first two.
Exactly, but after the first two are applied, this is no longer a function, but a Num a => Sometimes a. Indeed, if we determines the types, we see that Thing (+) :: Num a => Sometimes (a -> a -> a) and Thing 1 :: Num b => Sometimes b, so that means that Thing (+) <*> Thing 1 has type Num a => Sometimes (a -> a).
Then we determine the type of Thing (+) <*> Thing 1 <*> Thing 1, since Thing (+) <*> Thing 1 has type Num a => Sometimes (a -> a), and the last Thing 1 has type Num c => Sometimes c, it means that Thing (+) <*> Thing 1 <*> Thing 1 has type Num a => Sometimes a, but this is not a function, unless there is a Num type that is a function, which is what the error is saying.
what are those operators in haskell? and <*>
I have them in a line like this:
class Evaluable e where
eval :: (Num a, Ord a) => (Ident -> Maybe a) -> (e a) -> (Either String a)
typeCheck :: (Ident -> String) -> (e a) -> Bool
instance Evaluable NExpr where
eval lookup (Plus left right) = (+) <$> eval lookup left <*> eval lookup right
As I am the one who showed you these operators, I'll give a brief explanation as to why I used them.
To review, a functor is a type constructor that lets you use the fmap function to apply a function to a "wrapped" value. In the specific case of the Either type constructor (partially applied, in this case, to String), you can apply a function to a Right value, but ignore the function if applied to a Left value (your error). It provides a way of error propagation without having to check for the error.
fmap f (Right x) = Right (f x)
fmap f (Left y) = Left y
An applicative functor is similar, except the function itself can be wrapped just like the argument it is applied to. The <*> operator unwraps both its operands, unlike fmap which only unwraps its right operand.
Right f <*> Right x = Right (f x)
Left f <*> _ = Left f
_ <*> Left y = Left y
Typically, you don't wrap functions yourself: they result from using fmap to partially apply a function to a wrapped value:
fmap (+) (Right 3) == Right (+ 3)
fmap (+) (Left "error") == Left "error"
So, when we are working with Either values, the use of <$> (infix fmap) and <*> let us pretend we are working with regular values, without worrying about whether they are wrapped with Left or Right. Right values provide the expected Right-wrapped answer, and Left values are preserved. In the case of a binary operator, only the first Left value is returned, but that is often sufficient.
(+) <$> Left "x undefined" <*> Left "y undefined" == Left "x undefined" <*> Left "y undefined"
== Left "x undefined"
(+) <$> Left "x undefined" <*> Right 9 == Left "x undefined" <*> Right 9
== Left "x undefined"
(+) <$> Right 3 <*> Left "y undefined" == Right (+ 3) <*> Left "y undefined"
== Left "y undefined"
(+) <$> Right 3 <*> Right 9 == Right (+3) <*> Right 9
== Right 12
In the end, using the Applicative instance of Either String lets us combine the results of evaluating two subexpressions without having to explicitly check if either recursive call of eval actually succeeded. Successful recursive calls result in success; an error in either call is used as the same error for the top-level call.
The <$> operator is an infix form of fmap. It allows you to apply a pure function to the value wrapped into some parametric type that belongs to a Functor class. The type of <$> is (a -> b) -> f a -> f b.
The <*> operator is quite similar to <$>. It allows you to apply a function wrapped into a parametric type to a value wrapped into the same parametric type. The type of <*> is f (a -> b) -> f a -> f b.
In this particular case, it's a way to combine the results of eval.
If one part of the the expression is failing, then the whole expression is failing.
This way, its possible to separate error handling of your application logic and to avoid complex nested case ... of.
To fully understand this, I'll advise do read on functors first, then applicative functors.
In parallel you can play with Maybe and Either, and write the equivalent code using case expressions.
I just read the following from typeclassopedia about the difference between Monad and Applicative. I can understand that there is no join in Applicative. But the following description looks vague to me and I couldn't figure out what exactly is meant by "the result" of a monadic computation/action. So, if I put a value into Maybe, which makes a monad, what is the result of this "computation"?
Let’s look more closely at the type of (>>=). The basic intuition is
that it combines two computations into one larger computation. The
first argument, m a, is the first computation. However, it would be
boring if the second argument were just an m b; then there would be no
way for the computations to interact with one another (actually, this
is exactly the situation with Applicative). So, the second argument to
(>>=) has type a -> m b: a function of this type, given a result of
the first computation, can produce a second computation to be run.
... Intuitively, it is this ability to use the output from previous
computations to decide what computations to run next that makes Monad
more powerful than Applicative. The structure of an Applicative
computation is fixed, whereas the structure of a Monad computation can
change based on intermediate results.
Is there a concrete example illustrating "ability to use the output from previous computations to decide what computations to run next", which Applicative does not have?
My favorite example is the "purely applicative Either". We'll start by analyzing the base Monad instance for Either
instance Monad (Either e) where
return = Right
Left e >>= _ = Left e
Right a >>= f = f a
This instance embeds a very natural short-circuiting notion: we proceed from left to right and once a single computation "fails" into the Left then all the rest do as well. There's also the natural Applicative instance that any Monad has
instance Applicative (Either e) where
pure = return
(<*>) = ap
where ap is nothing more than left-to-right sequencing before a return:
ap :: Monad m => m (a -> b) -> m a -> m b
ap mf ma = do
f <- mf
a <- ma
return (f a)
Now the trouble with this Either instance comes to light when you'd like to collect error messages which occur anywhere in a computation and somehow produce a summary of errors. This flies in the face of short-circuiting. It also flies in the face of the type of (>>=)
(>>=) :: m a -> (a -> m b) -> m b
If we think of m a as "the past" and m b as "the future" then (>>=) produces the future from the past so long as it can run the "stepper" (a -> m b). This "stepper" demands that the value of a really exists in the future... and this is impossible for Either. Therefore (>>=) demands short-circuiting.
So instead we'll implement an Applicative instance which cannot have a corresponding Monad.
instance Monoid e => Applicative (Either e) where
pure = Right
Now the implementation of (<*>) is the special part worth considering carefully. It performs some amount of "short-circuiting" in its first 3 cases, but does something interesting in the fourth.
Right f <*> Right a = Right (f a) -- neutral
Left e <*> Right _ = Left e -- short-circuit
Right _ <*> Left e = Left e -- short-circuit
Left e1 <*> Left e2 = Left (e1 <> e2) -- combine!
Notice again that if we think of the left argument as "the past" and the right argument as "the future" then (<*>) is special compared to (>>=) as it's allowed to "open up" the future and the past in parallel instead of necessarily needing results from "the past" in order to compute "the future".
This means, directly, that we can use our purely Applicative Either to collect errors, ignoring Rights if any Lefts exist in the chain
> Right (+1) <*> Left [1] <*> Left [2]
> Left [1,2]
So let's flip this intuition on its head. What can we not do with a purely applicative Either? Well, since its operation depends upon examining the future prior to running the past, we must be able to determine the structure of the future without depending upon values in the past. In other words, we cannot write
ifA :: Applicative f => f Bool -> f a -> f a -> f a
which satisfies the following equations
ifA (pure True) t e == t
ifA (pure False) t e == e
while we can write ifM
ifM :: Monad m => m Bool -> m a -> m a -> m a
ifM mbool th el = do
bool <- mbool
if bool then th else el
such that
ifM (return True) t e == t
ifM (return False) t e == e
This impossibility arises because ifA embodies exactly the idea of the result computation depending upon the values embedded in the argument computations.
Just 1 describes a "computation", whose "result" is 1. Nothing describes a computation which produces no results.
The difference between a Monad and an Applicative is that in the Monad there's a choice. The key distinction of Monads is the ability to choose between different paths in computation (not just break out early). Depending on a value produced by a previous step in computation, the rest of computation structure can change.
Here's what this means. In the monadic chain
return 42 >>= (\x ->
if x == 1
then
return (x+1)
else
return (x-1) >>= (\y ->
return (1/y) ))
the if chooses what computation to construct.
In case of Applicative, in
pure (1/) <*> ( pure (+(-1)) <*> pure 1 )
all the functions work "inside" computations, there's no chance to break up a chain. Each function just transforms a value it's fed. The "shape" of the computation structure is entirely "on the outside" from the functions' point of view.
A function could return a special value to indicate failure, but it can't cause next steps in the computation to be skipped. They all will have to process the special value in a special way too. The shape of the computation can not be changed according to received value.
With monads, the functions themselves construct computations to their choosing.
Here is my take on #J. Abrahamson's example as to why ifA cannot use the value inside e.g. (pure True). In essence, it still boils down to the absence of the join function from Monad in Applicative, which unifies the two different perspectives given in typeclassopedia to explain the difference between Monad and Applicative.
So using #J. Abrahamson's example of purely applicative Either:
instance Monoid e => Applicative (Either e) where
pure = Right
Right f <*> Right a = Right (f a) -- neutral
Left e <*> Right _ = Left e -- short-circuit
Right _ <*> Left e = Left e -- short-circuit
Left e1 <*> Left e2 = Left (e1 <> e2) -- combine!
(which has similar short-circuiting effect to the Either Monad), and the ifA function
ifA :: Applicative f => f Bool -> f a -> f a -> f a
What if we try to achieve the mentioned equations:
ifA (pure True) t e == t
ifA (pure False) t e == e
?
Well, as already pointed out, ultimately, the content of (pure True), cannot be used by a later computation. But technically speaking, this isn't right. We can use the content of (pure True) since a Monad is also a Functor with fmap. We can do:
ifA' b t e = fmap (\x -> if x then t else e) b
The problem is with the return type of ifA', which is f (f a). In Applicative, there is no way of collapsing two nested ApplicativeS into one. But this collapsing function is precisely what join in Monad performs. So,
ifA = join . ifA'
will satisfy the equations for ifA, if we can implement join appropriately. What Applicative is missing here is exactly the join function. In other words, we can somehow use the result from the previous result in Applicative. But doing so in an Applicative framework will involve augmenting the type of the return value to a nested applicative value, which we have no means to bring back to a single-level applicative value. This will be a serious problem because, e.g., we cannot compose functions using ApplicativeS appropriately. Using join fixes the issue, but the very introduction of join promotes the Applicative to a Monad.
The key of the difference can be observed in the type of ap vs type of =<<.
ap :: m (a -> b) -> (m a -> m b)
=<< :: (a -> m b) -> (m a -> m b)
In both cases there is m a, but only in the second case m a can decide whether the function (a -> m b) gets applied. In its turn, the function (a -> m b) can "decide" whether the function bound next gets applied - by producing such m b that does not "contain" b (like [], Nothing or Left).
In Applicative there is no way for functions "inside" m (a -> b) to make such "decisions" - they always produce a value of type b.
f 1 = Nothing -- here f "decides" to produce Nothing
f x = Just x
Just 1 >>= f >>= g -- g doesn't get applied, because f decided so.
In Applicative this is not possible, so can't show a example. The closest is:
f 1 = 0
f x = x
g <$> f <$> Just 1 -- oh well, this will produce Just 0, but can't stop g
-- from getting applied
But the following description looks vague to me and I couldn't figure out what exactly is meant by "the result" of a monadic computation/action.
Well, that vagueness is somewhat deliberate, because what "the result" is of a monadic computation is something that depends on each type. The best answer is a bit tautological: the "result" (or results, since there can be more than one) is whatever value(s) the instance's implementation of (>>=) :: Monad m => m a -> (a -> m b) -> m b invokes the function argument with.
So, if I put a value into Maybe, which makes a monad, what is the result of this "computation"?
The Maybe monad looks like this:
instance Monad Maybe where
return = Just
Nothing >>= _ = Nothing
Just a >>= k = k a
The only thing in here that qualifies as a "result" is the a in the second equation for >>=, because it's the only thing that ever gets "fed" to the second argument of >>=.
Other answers have gone into depth about the ifA vs. ifM difference, so I thought I'd highlight another significant difference: applicatives compose, monads don't. With Monads, if you want to make a Monad that combines the effects of two existing ones, you have to rewrite one of them as a monad transformer. In contrast, if you have two Applicatives you can easily make a more complex one out of them, as shown below. (Code is copypasted from transformers.)
-- | The composition of two functors.
newtype Compose f g a = Compose { getCompose :: f (g a) }
-- | The composition of two functors is also a functor.
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose x) = Compose (fmap (fmap f) x)
-- | The composition of two applicatives is also an applicative.
instance (Applicative f, Applicative g) => Applicative (Compose f g) where
pure x = Compose (pure (pure x))
Compose f <*> Compose x = Compose ((<*>) <$> f <*> x)
-- | The product of two functors.
data Product f g a = Pair (f a) (g a)
-- | The product of two functors is also a functor.
instance (Functor f, Functor g) => Functor (Product f g) where
fmap f (Pair x y) = Pair (fmap f x) (fmap f y)
-- | The product of two applicatives is also an applicative.
instance (Applicative f, Applicative g) => Applicative (Product f g) where
pure x = Pair (pure x) (pure x)
Pair f g <*> Pair x y = Pair (f <*> x) (g <*> y)
-- | The sum of a functor #f# with the 'Identity' functor
data Lift f a = Pure a | Other (f a)
-- | The sum of two functors is always a functor.
instance (Functor f) => Functor (Lift f) where
fmap f (Pure x) = Pure (f x)
fmap f (Other y) = Other (fmap f y)
-- | The sum of any applicative with 'Identity' is also an applicative
instance (Applicative f) => Applicative (Lift f) where
pure = Pure
Pure f <*> Pure x = Pure (f x)
Pure f <*> Other y = Other (f <$> y)
Other f <*> Pure x = Other (($ x) <$> f)
Other f <*> Other y = Other (f <*> y)
Now, if we add in the Constant functor/applicative:
newtype Constant a b = Constant { getConstant :: a }
instance Functor (Constant a) where
fmap f (Constant x) = Constant x
instance (Monoid a) => Applicative (Constant a) where
pure _ = Constant mempty
Constant x <*> Constant y = Constant (x `mappend` y)
...we can assemble the "applicative Either" from the other responses out of Lift and Constant:
type Error e a = Lift (Constant e) a
As #Will Ness explains in his answer, the key difference is that with Monads there's a choice between different executions paths at every step. Let's make this potential choice syntactically visible by implementing a function for sequencing four times. First for applicative f, and then for monad m:
seq4A :: Applicative f => f a -> f [a]
seq4A f =
f <**> (
f <**> (
f <**> (
f <&> (\a1 a2 a3 a4 ->
[a1, a2, a3, a4]))))
seq4M :: Monad m => m a -> m [a]
seq4M m =
m >>= (\a1 ->
m >>= (\a2 ->
m >>= (\a3 ->
m >>= (\a4 ->
return [a1, a2, a3, a4]))))
The seq4M function has the values resulting from the monadic action available at every step and could thus make a choice at every step. On the other hand the seq4A function only has the values available at the very end.
I would like to share my view on this "iffy miffy" thing, as I understand this everything inside the context get applied, so for example:
iffy :: Applicative f => f Bool -> f a -> f a -> f a
iffy fb ft fe = cond <$> fb <*> ft <*> fe where
cond b t e = if b then t else e
case 1>> iffy (Just True) (Just “True”) Nothing ->> Nothing
upps should be Just "True" ... but
case 2>> iffy (Just False) (Just “True”) (Just "False") ->> Just "False"
(the "good" choice is made inside the context)
I explained this to myself this way, just before the end of the computation in case >>1 we get something like that in the "chain" :
Just (Cond True "True") <*> something [something being "accidentaly" Nothing]
which according by definition of Applicative is evaluated as:
fmap (Cond True "True") something
which when "something" is Nothing becomes a Nothing according to Functor constraint (fmap over Nothing gives Nothing). And it is not possible to define a Functor with "fmap f Nothing = something" end of story.
I have to give a (simple) talk about Yesod. And yes,.. i've never or really really rarely used haskell as well.
University lecturer.....huh.
So i read a book about yesod and in some chapters the author is using some operators like <$> and <*>.
Can someone explain in easy words, what this operators do? Its pretty hard to google for that chars and if tried to read the documentation of Control.Applicative but to be honest, its hard to get for an haskell beginner.
so i hope anyone have a simple answer for me :)
an example of the book where these operators are used:
......
personForm :: Html -> MForm Handler (FormResult Person, Widget)
personForm = renderDivs $ Person
<$> areq textField "Name" Nothing
<*> areq (jqueryDayField def
{ jdsChangeYear = True -- give a year dropdown
, jdsYearRange = "1900:-5" -- 1900 till five years ago
}) "Birthday" Nothing
<*> aopt textField "Favorite color" Nothing
<*> areq emailField "Email address" Nothing
<*> aopt urlField "Website" Nothing
data Person = Person
{ personName :: Text
, personBirthday :: Day
, personFavoriteColor :: Maybe Text
, personEmail :: Text
, personWebsite :: Maybe Text
}
deriving Show
.....
.....................................
Hey,
Thanks a lot and amazingly most of the answers are useful. Sadly a only can hit "solved" on one answer.
Thanks a lot, the tutorial (that I really didn't find on Google) is pretty good
I am always very careful when making answers that are made up mostly of links, but this is one amazing tutorial that explains Functors, Applicatives and gives a bit of understaning on Monads.
The simplest answer is the type, of course. These operators come from type typeclasses Functor and its subclass Applicative.
class Functor f where
fmap :: (a -> b) -> (f a -> f b)
(<$>) = fmap -- synonym
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
The simplest intuitive answer is that Functors and Applicatives let you annotate simple values with "metadata" and (<$>), (<*>), and friends let you transform your "regular" value-level functions to work on "annotated" values.
go x y -- works if x and y are regular values
go <$> pure x <*> pure y -- uses `pure` to add "default" metadata
-- but is otherwise identical to the last one
Like any simple answer, it's kind of a lie, though. "Metadata" is a very oversimplified term. Better ones are "computational context" or "effect context" or "container".
If you're familiar with Monads then you are already very familiar with this concept. All Monads are Applicatives and so you can think of (<$>) and (<*>) as providing an alternative syntax for some do notation
do x_val <- x go <$> x
y_val <- y <*> y
return (go x_val y_val)
It has fewer symbols and emphasizes the idea of "applying" go to two arguments instead of emphasizing the imperative notion of "get the value that x generates, then get the value that y generates, then apply those values to go, then re-wrap the result" like do syntax does.
One final intuition I can throw out there is to think of Applicative in a very different way. Applicative is equivalent to another class called Monoidal.
class Functor f => Monoidal f where
init :: f () -- similar to pure
prod :: f a -> f b -> f (a, b) -- similar to (<*>)
so that Monoidal Functors let you (a) instantiate them with a trivial value
init :: [()]
init = []
init :: Maybe ()
init = Just ()
and also smash two of them together to produce their product
prod :: [a] -> [b] -> [(a, b)]
prod as bs = [(a, b) | a <- as, b <- bs]
prod :: Maybe a -> Maybe b -> Maybe (a, b)
prod (Just a) (Just b) = (Just (a, b))
prod _ _ = Nothing
This means that with a Monoidal functor you can smash a whole lot of values together and then fmap a value-level function over the whole bunch
go <$> maybeInt `prod` (maybeChar `prod` maybeBool) where
go :: (Int, (Char, Bool)) -> Double -- it's pure!
go (i, (c, b)) = ...
which is essentially what you're doing with (<$>) and (<*>), just with fewer tuples
go <$> maybeInt <*> maybeChar <*> maybeBool where
go :: Int -> Char -> Bool -> Double
go i c b = ...
Finally, here's how you convert between the two notions
-- forward
init = pure ()
prod x y = (,) <$> x <*> y
-- back
pure a = const a <$> init
f <*> x = ($) <$> prod f x
which shows how you can think of (<*>) as taking a normal value-level application ($) and injecting it up into the product inside of the Functor.
I don't suppose it helps to say that <$> is just an infix synonym for fmap. However, maybe these examples help clarify:
GHCi> (*2) <$> (Just 3)
Just 6
GHCi> (*2) <$> (Nothing)
Nothing
GHCi> (*3) <$> (Right 7)
Right 21
GHCi> (*2) <$> (Left "error")
Left "error"
GHCi> (+ 1) <$> [2,4,6,8]
[3,5,7,9]
Now compare that to this:
GHCi> (*) <$> (Just 2) <*> (Just 5)
Just 10
GHCi> (*) <$> (Just 2) <*> (Nothing)
Nothing
GHCi> (*) <$> (Right 3) <*> (Right 7)
Right 21
GHCi> (*) <$> (Left "error") <*> (Right 7)
Left "error"
GHCi> (+) <$> [1,2,3] <*> [10,20,30]
[11,21,31,12,22,32,13,23,33]
GHCi> (+) <$> [1,2,3] <*> []
[]
And then to this:
GHCi> (Just (*2)) <*> (Just 5)
Just 10
GHCi> (Right (*3)) <*> (Right 7)
Right 21
GHCi> [(+1),(+2),(+3)] <*> [10,20,30]
[11,21,31,12,22,32,13,23,33]
Really, that should show you all you need to know for lecture purposes, assuming you have learned from this that (*) <$> (Just 2) <*> (Just 5) is equivalent to Just (2 * 5)
(In the first set of examples, by the way, the functions on the left hand side are all applicatives.)
Put simply, <$> takes the function on the left and lifts it into the context of the "things in boxes" on the right, so that it can be applied to the things in boxes, in a way that obeys the special rules of the boxes (e.g. Nothng causing the whole chain to fail).
<*> takes a partially-bound function in a box on the left and applies it to the value in a box on the right. A partially bound function being one which has been given some but not all of its arguments. So (*) <$> (Right 3) <*> (Right 7) <*> (Right 4) would fail - with a not-very-helpful error message - because once * has been applied to 3 and 7 it is no longer a partial function and nobody knows what to do with the 4.
Used together, <$> and <*> allow a function to be applied to its arguments, all inside a box. You get the result in a box.
This can all only be done if the box is itself a functor; that is the crucial constraint for all of this. A functor is a function for which somebody has defined an fmap function which allows it to be transformed from a function that applies to one type into a function that applies to another type (while not changing the essential character of the function). If you like, Monads (boxes for things) know how to transform functions so that they can be applied to their things.
If you're not ready to learn about functors, applicatives, and monads yet, this may give you an intuition for how to use <$> and <*>. (I myself learned how to use them by looking at examples, before I really understood that other stuff.) Without the <$> and <*>, the first part of that code would look something like this:
......
personForm :: Html -> MForm Handler (FormResult Person, Widget)
personForm = do
name <- areq textField "Name" Nothing
bday <- areq (jqueryDayField def
{ jdsChangeYear = True -- give a year dropdown
, jdsYearRange = "1900:-5" -- 1900 till five years ago
}) "Birthday" Nothing
colour <- aopt textField "Favorite color" Nothing
email <- areq emailField "Email address" Nothing
url <- aopt urlField "Website" Nothing
renderDivs $ Person name bday colour email url
In other words, <$> and <*> can eliminate the need to create a lot of symbols that we only use once.
Earlier I asked about translating monadic code to use only the applicative functor instance of Parsec. Unfortunately I got several replies which answered the question I literally asked, but didn't really give me much insight. So let me try this again...
Summarising my knowledge so far, an applicative functor is something which is somewhat more restricted than a monad. In the tradition of "less is more", restricting what the code can do increases the possibilities for crazy code manipulation. Regardless, a lot of people seem to believe that using applicative instead of monad is a superior solution where it's possible.
The Applicative class is defined in Control.Applicative, whose Haddock's listing helpfully separates the class methods and utility functions with a vast swathe of class instances between them, to make it hard to quickly see everything on screen at once. But the pertinent type signatures are
pure :: x -> f x
<*> :: f (x -> y) -> f x -> f y
*> :: f x -> f y -> f y
<* :: f x -> f y -> f x
<$> :: (x -> y) -> f x -> f y
<$ :: x -> f y -> f x
Makes perfect sense, right?
Well, Functor already gives us fmap, which is basically <$>. I.e., given a function from x to y, we can map an f x to an f y. Applicative adds two essentially new elements. One is pure, which has roughly the same type as return (and several other operators in various category theory classes). The other is <*>, which gives us the ability to take a container of functions and a container of inputs and produce a container of outputs.
Using the operators above, we can very neatly do something such as
foo <$> abc <*> def <*> ghi
This allows us to take an N-ary function and source its arguments from N functors in a way which generalises easily to any N.
This much I already understand. There are two main things which I do not yet understand.
First, the functions *>, <* and <$. From their types, <* = const, *> = flip const, and <$ could be something similar. Presumably this does not describe what these functions actually do though. (??!)
Second, when writing a Parsec parser, each parsable entity usually ends up looking something like this:
entity = do
var1 <- parser1
var2 <- parser2
var3 <- parser3
...
return $ foo var1 var2 var3...
Since an applicative functor does not allow us to bind intermediate results to variables in this way, I'm puzzled as to how to gather them up for the final stage. I haven't been able to wrap my mind around the idea fully enough in order to comprehend how to do this.
The <* and *> functions are very simple: they work the same way as >>. The <* would work the same way as << except << does not exist. Basically, given a *> b, you first "do" a, then you "do" b and return the result of b. For a <* b, you still first "do" a then "do" b, but you return the result of a. (For appropriate meanings of "do", of course.)
The <$ function is just fmap const. So a <$ b is equal to fmap (const a) b. You just throw away the result of an "action" and return a constant value instead. The Control.Monad function void, which has a type Functor f => f a -> f () could be written as () <$.
These three functions are not fundamental to the definition of an applicative functor. (<$, in fact, works for any functor.) This, again, is just like >> for monads. I believe they're in the class to make it easier to optimize them for specific instances.
When you use applicative functors, you do not "extract" the value from the functor. In a monad, this is what >>= does, and what foo <- ... desugars to. Instead, you pass the wrapped values into a function directly using <$> and <*>. So you could rewrite your example as:
foo <$> parser1 <*> parser2 <*> parser3 ...
If you want intermediate variables, you could just use a let statement:
let var1 = parser1
var2 = parser2
var3 = parser3 in
foo <$> var1 <*> var2 <*> var3
As you correctly surmised, pure is just another name for return. So, to make the shared structure more obvious, we can rewrite this as:
pure foo <*> parser1 <*> parser2 <*> parser3
I hope this clarifies things.
Now just a little note. People do recommend using applicative functor functions for parsing. However, you should only use them if they make more sense! For sufficiently complex things, the monad version (especially with do-notation) can actually be clearer. The reason people recommend this is that
foo <$> parser1 <*> parser2 <*> parser3
is both shorter and more readable than
do var1 <- parser1
var2 <- parser2
var3 <- parser3
return $ foo var1 var2 var3
Essentially, the f <$> a <*> b <*> c is essentially like lifted function application. You can imagine the <*> being a replacement for a space (e.g. function application) in the same way that fmap is a replacement for function application. This should also give you an intuitive notion of why we use <$>--it's like a lifted version of $.
I can make a few remarks here, hopefully helpful. This reflects my understanding which itself might be wrong.
pure is unusually named. Usually functions are named referring to what they produce, but in pure x it is x that is pure. pure x produces an applicative functor which "carries" the pure x. "Carries" of course is approximate. An example: pure 1 :: ZipList Int is a ZipList, carrying a pure Int value, 1.
<*>, *>, and <* are not functions, but methods (this answers your first concern). f in their types is not general (like it would be, for functions) but specific, as specified by a specific instance. That's why they are indeed not just $, flip const and const. The specialized type f specifies the semantics of combination. In the usual applicative style programming, combination means application. But with functors, an additional dimension is present, represented by the "carrier" type f. In f x, there is a "contents", x, but there is also a "context", f.
The "applicative functors" style sought to enable the "applicative style" programming, with effects. Effects being represented by functors, carriers, providers of context; "applicative" referring to the normal applicative style of functional application. Writing just f x to denote application was once a revolutionary idea. There was no need for additional syntax anymore, no (funcall f x), no CALL statements, none of this extra stuff - combination was application... Not so, with effects, seemingly - there was again that need for the special syntax, when programming with effects. The slain beast reappeared again.
So came the Applicative Programming with Effects to again make the combination mean just application - in the special (perhaps effectful) context, if they were indeed in such context. So for a :: f (t -> r) and b :: f t, the (almost plain) combination a <*> b is an application of carried contents (or types t -> r and t), in a given context (of type f).
The main distinction from monads is, monads are non-linear. In
do { x <- a
; y <- b x
; z <- c x y
; return
(x, y, z) }
the computation b x depends on x, and c x y depends on both x and y. The functions are nested:
a >>= (\x -> b x >>= (\y -> c x y >>= (\z -> .... )))
If b and c do not depend on the previous results (x, y), this can be made flat by making the computation stages return repackaged, compound data (this addresses your second concern):
a >>= (\x -> b >>= (\y-> return (x,y))) -- `b ` sic
>>= (\(x,y) -> c >>= (\z-> return (x,y,z))) -- `c `
>>= (\(x,y,z) -> ..... )
and this is essentially an applicative style (b, c are fully known in advance, independent of the value x produced by a, etc.). So when your combinations create data that encompass all the information they need for further combinations, and there's no need for "outer variables" (i.e. all computations are already fully known, independent of any values produced by any of the previous stages), you can use this style of combination.
But if your monadic chain has branches dependent on values of such "outer" variables (i.e. results of previous stages of monadic computation), then you can't make a linear chain out of it. It is essentially monadic then.
As an illustration, the first example from that paper shows how the "monadic" function
sequence :: [IO a] → IO [a]
sequence [ ] = return [ ]
sequence (c : cs) = do
{ x <- c
; xs <- sequence cs -- `sequence cs` fully known, independent of `x`
; return
(x : xs) }
can actually be coded in this "flat, linear" style as
sequence :: (Applicative f) => [f a] -> f [a]
sequence [] = pure []
sequence (c : cs) = pure (:) <*> c <*> sequence cs
-- (:) x xs
There's no use here for the monad's ability to branch on previous results.
a note on the excellent Petr Pudlák's answer: in my "terminology" here, his pair is combination without application. It shows that the essence of what the Applictive Functors add to plain Functors, is the ability to combine. Application is then achieved by the good old fmap. This suggests combinatory functors as perhaps a better name (update: in fact, "Monoidal Functors" is the name).
You can view functors, applicatives and monads like this: They all carry a kind of "effect" and a "value". (Note that the terms "effect" and "value" are only approximations - there doesn't actually need to be any side effects or values - like in Identity or Const.)
With Functor you can modify possible values inside using fmap, but you cannot do anything with effects inside.
With Applicative, you can create a value without any effect with pure, and you can sequence effects and combine their values inside. But the effects and values are separate: When sequencing effects, an effect cannot depend on the value of a previous one. This is reflected in <*, <*> and *>: They sequence effects and combine their values, but you cannot examine the values inside in any way.
You could define Applicative using this alternative set of functions:
fmap :: (a -> b) -> (f a -> f b)
pureUnit :: f ()
pair :: f a -> f b -> f (a, b)
-- or even with a more suggestive type (f a, f b) -> f (a, b)
(where pureUnit doesn't carry any effect)
and define pure and <*> from them (and vice versa). Here pair sequences two effects and remembers the values of both of them. This definition expresses the fact that Applicative is a monoidal functor.
Now consider an arbitrary (finite) expression consisting of pair, fmap, pureUnit and some primitive applicative values. We have several rules we can use:
fmap f . fmap g ==> fmap (f . g)
pair (fmap f x) y ==> fmap (\(a,b) -> (f a, b)) (pair x y)
pair x (fmap f y) ==> -- similar
pair pureUnit y ==> fmap (\b -> ((), b)) y
pair x pureUnit ==> -- similar
pair (pair x y) z ==> pair x (pair y z)
Using these rules, we can reorder pairs, push fmaps outwards and eliminate pureUnits, so eventually such expression can be converted into
fmap pureFunction (x1 `pair` x2 `pair` ... `pair` xn)
or
fmap pureFunction pureUnit
So indeed, we can first collect all effects together using pair and then modify the resulting value inside using a pure function.
With Monad, an effect can depend on the value of a previous monadic value. This makes them so powerful.
The answers already given are excellent, but there's one small(ish) point I'd like to spell out explicitly, and it has to do with <*, <$ and *>.
One of the examples was
do var1 <- parser1
var2 <- parser2
var3 <- parser3
return $ foo var1 var2 var3
which can also be written as foo <$> parser1 <*> parser2 <*> parser3.
Suppose that the value of var2 is irrelevant for foo - e.g. it's just some separating whitespace. Then it also doesn't make sense to have foo accept this whitespace only to ignore it. In this case foo should have two parameters, not three. Using do-notation, you can write this as:
do var1 <- parser1
parser2
var3 <- parser3
return $ foo var1 var3
If you wanted to write this using only <$> and <*> it should be something like one of these equivalent expressions:
(\x _ z -> foo x z) <$> parser1 <*> parser2 <*> parser3
(\x _ -> foo x) <$> parser1 <*> parser2 <*> parser3
(\x -> const (foo x)) <$> parser1 <*> parser2 <*> parser3
(const . foo) <$> parser1 <*> parser2 <*> parser3
But that's kind of tricky to get right with more arguments!
However, you can also write foo <$> parser1 <* parser2 <*> parser3. You could call foo the semantic function which is fed the result of parser1 and parser3 while ignoring the result of parser2 in between. The absence of > is meant to be indicative of the ignoring.
If you wanted to ignore the result of parser1 but use the other two results, you can similarly write foo <$ parser1 <*> parser2 <*> parser3, using <$ instead of <$>.
I've never found much use for *>, I would normally write id <$ p1 <*> p2 for the parser that ignores the result of p1 and just parses with p2; you could write this as p1 *> p2 but that increases the cognitive load for readers of the code.
I've learnt this way of thinking just for parsers, but it has later been generalised to Applicatives; but I think this notation comes from the uuparsing library; at least I used it at Utrecht 10+ years ago.
I'd like to add/reword a couple things to the very helpful existing answers:
Applicatives are "static". In pure f <*> a <*> b, b does not depend on a, and so can be analyzed statically. This is what I was trying to show in my answer to your previous question (but I guess I failed -- sorry) -- that since there was actually no sequential dependence of parsers, there was no need for monads.
The key difference that monads bring to the table is (>>=) :: Monad m => m a -> (a -> m b) -> m a, or, alternatively, join :: Monad m => m (m a). Note that whenever you have x <- y inside do notation, you're using >>=. These say that monads allow you to use a value "inside" a monad to produce a new monad, "dynamically". This cannot be done with an Applicative. Examples:
-- parse two in a row of the same character
char >>= \c1 ->
char >>= \c2 ->
guard (c1 == c2) >>
return c1
-- parse a digit followed by a number of chars equal to that digit
-- assuming: 1) `digit`s value is an Int,
-- 2) there's a `manyN` combinator
-- examples: "3abcdef" -> Just {rest: "def", chars: "abc"}
-- "14abcdef" -> Nothing
digit >>= \d ->
manyN d char
-- note how the value from the first parser is pumped into
-- creating the second parser
-- creating 'half' of a cartesian product
[1 .. 10] >>= \x ->
[1 .. x] >>= \y ->
return (x, y)
Lastly, Applicatives enable lifted function application as mentioned by #WillNess.
To try to get an idea of what the "intermediate" results look like, you can look at the parallels between normal and lifted function application. Assuming add2 = (+) :: Int -> Int -> Int:
-- normal function application
add2 :: Int -> Int -> Int
add2 3 :: Int -> Int
(add2 3) 4 :: Int
-- lifted function application
pure add2 :: [] (Int -> Int -> Int)
pure add2 <*> pure 3 :: [] (Int -> Int)
pure add2 <*> pure 3 <*> pure 4 :: [] Int
-- more useful example
[(+1), (*2)]
[(+1), (*2)] <*> [1 .. 5]
[(+1), (*2)] <*> [1 .. 5] <*> [3 .. 8]
Unfortunately, you can't meaningfully print the result of pure add2 <*> pure 3 for the same reason that you can't for add2 ... frustrating. You may also want to look at the Identity and its typeclass instances to get a handle on Applicatives.