4

After having read Anthony's response on a style-related parser question, I was trying to convince myself that writing monadic parsers can still be rather compact.

So instead of

reference :: Parser Transc
reference = try $ do string "#{"
                     a <- number
                     char ','
                     b <- number
                     char ','
                     c <- number
                     char '}'
                     return $ Outside (a,b,c)

We can simply have:

reference3 :: Parser Transc
reference3 = liftM3 (((Outside .).) .  (,,)) 
             (string "#{" >> number <<! char ',') 
             number
             (char ',' >> number <<! char '}') where 
               (<<!) = liftM2 const

Which is very similar to applicative version provided by Anthony:

reference2 :: Parser Transc
reference2 = ((Outside .) .) . (,,) 
             <$> (string "#{" *> number2 <* char ',') 
             <*> number2 
             <*> (char ',' *> number2 <* char '}')

...except for the <<! operator which is conceptually similar to <* which is defined as liftA2 const meaning "sequence but discard value and use value provided to the left".

Of course << would have been a bad name for liftM2 const, it would have suggested that << is equivalent to flip >> if we follow the same logic as >>= and =<<.

I don't find a "liftM2 const" under a single name. Is this because it is not that useful?

Community
  • 1
  • 1
gawi
  • 13,940
  • 7
  • 42
  • 78
  • 2
    Unrelated, why does your `Outside` constructor take a triple rather than having three arguments? The latter would make your code nicer. – augustss Oct 24 '11 at 11:30
  • @augustss It's not mine. I just took the example from someone else's post. Agreed that curried form would be better. – gawi Oct 24 '11 at 15:26

1 Answers1

10

I don't quite see the problem. Every monad is also an of applicative functor, so you can simply use (*>) in the monadic expressions as well.

(At the time of this answer (year 2011), Applicative was not a superclass of Monad, so it may have been necessary to add a corresponding class instance.)

Heinrich Apfelmus
  • 11,034
  • 1
  • 39
  • 67
  • 1
    Put another way, what would a similar operator whose type restricted it to `Monad` get you? These operators are for statically specifying the flow of a computation, which is exactly what `Applicative`s are for. – Anthony Oct 24 '11 at 16:59
  • Ok, I think I get the point. The root problem is that Applicative is not a superclass of Monad (unfortunate!). But trying to bring all the Applicative functions and operators to Monad is a silly exercice. It is much more simpler to add an Applicative instance and hence benefit from a more generic abstraction. – gawi Oct 24 '11 at 17:59
  • @gawi: Basically, `<<!` would just be a new name for an already existing function (namely `<*`). It's just that the latter function does not actually exist due to some very boring reason (namely that `Applicative` not a superclass of `Monad`). – Heinrich Apfelmus Oct 24 '11 at 18:21
  • @Heinrich Apfelmus But we have `<*>` and `ap`, `pure` and `return`, `*>` and `>>`. However, `<*` is the only function of `Applicative` not having a monadic equivalent. I can live with that but I was just wondering. – gawi Oct 24 '11 at 18:39
  • @HeinrichApfelmus *For historical reasons, `Applicative` is not a superclass of `Monad` [...]* You may want to update your answer, now that the Functor-Applicative-Monad proposal is in effect. – jub0bs Sep 06 '15 at 18:40