Search code examples
haskellmonadsdo-notation

Is do notation used necessarily in the context of monad?


Haskell report 2010 says

A do expression provides a more conventional syntax for monadic programming. It allows an expression such as

putStr "x: " >>
getLine >>= \l ->
return (words l)

to be written in a more traditional way as:

do putStr "x: "
   l <- getLine
   return (words l)

Haskell the Craft of Functional programming by Thompson says

We'll continue to use the do notation, but will keep in mind that it essentially boils down to the existence of a function (>>=) which does the work of sequencing I/O programs, and binding their results for future use.

Do the above mean that do notation is used necessarily in the context of monad?

If yes, why does the following functor use the do notation?

instance    Functor IO  where
    --  fmap    ::  (a  ->  b)  ->  IO  a   ->  IO  b
    fmap    g   mx  =   do  {x  <-  mx; return  (g  x)}

Solution

  • Yes. As the article quoted states, do-notation is simply syntactic sugar for the monad operations.

    These are the rules for de-sugaring do-notation:

    1. do {foobar; ...} = foobar >> do {...} (aka foobar >>= \_ -> do {...})
    2. do {a <- foobar; ...} = foobar >>= \a -> do {...}
    3. do {foobar} = foobar

    Necessarily this means that do-notation works entirely on monads, except in the trivial case that rule 3 describes.

    So for instance, as the article states, do {putStr "x: "; l <- getLine; return (words l)} is exactly equal to putStr "x: " >> (getLine >>= \l -> return (words l)), which you may confirm via the de-sugaring rules.

    In the definition for Functor IO you quote above, the Monad IO instance has already been defined, and so we are using it to define the Functor instance, too.

    It may also be useful to note that all monads are necessarily functors (see the definition of the Monad typeclass), so when one says do-notation works on monads, it also necessarily works on the functors as well. I suspect this may be a point of confusion.


    It is worth noting that in certain restricted cases, it is possible to use only Applicative operations rather than the more general Monad operations. For instance, the example the article provides could be written as putStr "x: " *> (pure words <*> getLine). There is an experimental language extension called ApplicativeDo which adds to GHC the capability to recognise these situations and generalise certain cases of do-notation to all applicatives, not just all monads.