Convert from Monad to Applied

OK, so I know what the Applicative type class contains, and why it is useful. But I canโ€™t completely cover my brain with how you will 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 could you write this without using a Monad instance for Parser ? Many people claim that this can be done and it is a good idea, but I canโ€™t understand how.

+17
haskell monads applicative
Feb 27 '13 at 22:16
source share
3 answers
 integer :: Parser Integer integer = read <$> (many1 space *> many1 digit) 

or

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

Do you think one of them is more readable is up to you.

+11
Feb 27 '13 at 22:19
source share

I would write

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

There is a bunch of legal associative operators (for example, applications) for parsers <$> , <*> , <$ , <* . The thing in the far left corner should be a pure function that collects the value of the result from the values โ€‹โ€‹of the component. The thing to the right of each operator must be a parser that collectively provides grammar components from left to right. Which operator to use depends on two options:

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

So, by choosing read :: String -> Integer as a pure function that will deliver analyzer semantics, we can classify the leading space as โ€œnoiseโ€ and the group of digits as โ€œsignalโ€, therefore

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

You can combine several features with

 p1 <|> ... <|> pn 

and express impossibility with

 empty 

It is rarely necessary to name components in parsers, and the resulting code is more like a grammar with added semantics.

+38
Feb 27 '13 at 23:05
source share

Your example can be completely rewritten in a form that more closely resembles an applicator:

 do many1 space ds <- many1 digit return $ read ds 
  • definition for do :

     many1 space >> (many1 digit >>= \ds -> return $ read ds) 
  • definition of $ :

     many1 space >> (many1 digit >>= \ds -> return (read ds)) 
  • definition . :

     many1 space >> (many1 digit >>= (return . read)) 
  • 3rd law of the monad (associativity):

     (many1 space >> many1 digit) >>= (return . read) 
  • definition of liftM (in the notation do not):

     liftM read (many1 space >> many1 digit) 

This (or should be if I didnโ€™t mess it up :)) is identical to the behavior of your example.

Now, if you replace liftM on fmap with <$> and >> with *> , you will get the Application:

 read <$> (many1 space *> many1 digit) 

This is true because liftM , fmap and <$> should usually be synonyms such as >> and *> .

All this works, and we can do it because the original example did not use the result of any parser to create the next analyzer.

+7
Mar 01 '13 at 14:07
source share



All Articles