Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Translate from monad to applicative

OK, so I know what the Applicative type class contains, and why that's useful. But I can't quite wrap my brain around how you'd use it in a non-trivial example.

Consider, for example, the following fairly simple Parsec parser:

integer :: Parser Integer
integer = do
  many1 space
  ds <- many1 digit
  return $ read ds

Now how the heck would you write that without using the Monad instance for Parser? Lots of people claim that this can be done and is a good idea, but I can't figure out how exactly.

like image 399
MathematicalOrchid Avatar asked Feb 27 '13 22:02

MathematicalOrchid


People also ask

Is monad an applicative?

An applicative is a data type that implements the Applicative typeclass. A monad is a data type that implements the Monad typeclass. A Maybe implements all three, so it is a functor, an applicative, and a monad.

Are all monads applicative?

Monads are not a replacement for applicative functors Instead, every monad is an applicative functor (as well as a functor). It is considered good practice not to use >>= if all you need is <*>, or even fmap.

Is maybe a functor or monad?

One of the simplest, and easiest to understand, functors is Maybe. It's also sometimes known as the Maybe monad, but this is not a monad tutorial; it's a functor tutorial. Maybe is many things; one of them is a functor. In F#, Maybe is called option .

What is applicative in functional programming?

In functional programming, an applicative functor, or an applicative for short, is an intermediate structure between functors and monads.


2 Answers

I'd write

integer :: Parser Integer
integer = read <$ many1 space <*> many1 digit

There's a bunch of left associative (like application) parser-building operators <$>, <*>, <$, <*. The thing in the far left should be the pure function which assembles the result value from the component values. The thing on the right of each operator should be a parser, collectively giving the components of the grammar left-to-right. Which operator to use depends on two choices, as follows.

  the thing to the right is    signal  / noise
  _________________________            
  the thing to the left is \           
                            +-------------------
                    pure /  |   <$>       <$
                  a parser  |   <*>       <*

So, having chosen read :: String -> Integer as the pure function which is going to deliver the semantics of the parser, we can classify the leading space as "noise" and the bunch of digits as "signal", hence

 read <$ many1 space <*> many1 digit
 (..)    (.........)     (.........)
 pure    noise parser     |
 (.................)      |
     parser              signal parser
 (.................................)
                    parser

You can combine multiple possibilities with

p1 <|> ... <|> pn

and express impossibility with

empty

It's seldom necessary to name components in parsers, and the resulting code looks more like a grammar with added semantics.

like image 183
pigworker Avatar answered Oct 15 '22 08:10

pigworker


integer :: Parser Integer
integer = read <$> (many1 space *> many1 digit)

Or

integer = const read <$> many1 space <*> many1 digit

Whether you think either of these are more readable is up to you.

like image 44
dave4420 Avatar answered Oct 15 '22 09:10

dave4420