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.
<$>
and<$
are not specific toApplicative
. They can work on anyFunctor
. – AJF<*
=const
,*>
=flip const
, and<$
could be something similar" (a side note, many years later) this would be the case for the typesf x -> g y -> f x
,f x -> g y -> g y
etc. – Will Ness