.. _monad-comprehensions:

Monad comprehensions
--------------------

.. index::
   single: monad comprehensions

.. extension:: MonadComprehensions
    :shortdesc: Enable monad comprehensions.

    :since: 7.2.1

    Enable list comprehension syntax for arbitrary monads.

Monad comprehensions generalise the list comprehension notation,
including parallel comprehensions (:ref:`parallel-list-comprehensions`)
and transform comprehensions (:ref:`generalised-list-comprehensions`) to
work for any monad.

Monad comprehensions support:

-  Bindings: ::

       [ x + y | x <- Just 1, y <- Just 2 ]

   Bindings are translated with the ``(>>=)`` and ``return`` functions
   to the usual do-notation: ::

       do x <- Just 1
          y <- Just 2
          return (x+y)

-  Guards: ::

       [ x | x <- [1..10], x <= 5 ]

   Guards are translated with the ``guard`` function, which requires an
   ``Alternative`` instance: ::

       do x <- [1..10]
          guard (x <= 5)
          return x

-  Transform statements (as with :extension:`TransformListComp`): ::

       [ x+y | x <- [1..10], y <- [1..x], then take 2 ]

   This translates to: ::

       do (x,y) <- take 2 (do x <- [1..10]
                              y <- [1..x]
                              return (x,y))
          return (x+y)

-  Group statements (as with :extension:`TransformListComp`):

   ::

       [ x | x <- [1,1,2,2,3], then group by x using GHC.Exts.groupWith ]
       [ x | x <- [1,1,2,2,3], then group using myGroup ]

-  Parallel statements (as with :extension:`ParallelListComp`):

   ::

       [ (x+y) | x <- [1..10]
               | y <- [11..20]
               ]

   Parallel statements are translated using the ``mzip`` function, which
   requires a ``MonadZip`` instance defined in
   :base-ref:`Control.Monad.Zip.`:

   ::

       do (x,y) <- mzip (do x <- [1..10]
                            return x)
                        (do y <- [11..20]
                            return y)
          return (x+y)

All these features are enabled by default if the :extension:`MonadComprehensions`
extension is enabled. The types and more detailed examples on how to use
comprehensions are explained in the previous chapters
:ref:`generalised-list-comprehensions` and
:ref:`parallel-list-comprehensions`. In general you just have to replace
the type ``[a]`` with the type ``Monad m => m a`` for monad
comprehensions.

.. note::
    Even though most of these examples are using the list monad, monad
    comprehensions work for any monad. The ``base`` package offers all
    necessary instances for lists, which make :extension:`MonadComprehensions`
    backward compatible to built-in, transform and parallel list
    comprehensions.

More formally, the desugaring is as follows. We write ``D[ e | Q]`` to
mean the desugaring of the monad comprehension ``[ e | Q]``:

.. code-block:: none

    Expressions: e
    Declarations: d
    Lists of qualifiers: Q,R,S

    -- Basic forms
    D[ e | ]               = return e
    D[ e | p <- e, Q ]  = e >>= \p -> D[ e | Q ]
    D[ e | e, Q ]          = guard e >> \p -> D[ e | Q ]
    D[ e | let d, Q ]      = let d in D[ e | Q ]

    -- Parallel comprehensions (iterate for multiple parallel branches)
    D[ e | (Q | R), S ]    = mzip D[ Qv | Q ] D[ Rv | R ] >>= \(Qv,Rv) -> D[ e | S ]

    -- Transform comprehensions
    D[ e | Q then f, R ]                  = f D[ Qv | Q ] >>= \Qv -> D[ e | R ]

    D[ e | Q then f by b, R ]             = f (\Qv -> b) D[ Qv | Q ] >>= \Qv -> D[ e | R ]

    D[ e | Q then group using f, R ]      = f D[ Qv | Q ] >>= \ys ->
                                            case (fmap selQv1 ys, ..., fmap selQvn ys) of
                                             Qv -> D[ e | R ]

    D[ e | Q then group by b using f, R ] = f (\Qv -> b) D[ Qv | Q ] >>= \ys ->
                                            case (fmap selQv1 ys, ..., fmap selQvn ys) of
                                               Qv -> D[ e | R ]

    where  Qv is the tuple of variables bound by Q (and used subsequently)
           selQvi is a selector mapping Qv to the ith component of Qv

    Operator     Standard binding       Expected type
    --------------------------------------------------------------------
    return       GHC.Base               t1 -> m t2
    (>>=)        GHC.Base               m1 t1 -> (t2 -> m2 t3) -> m3 t3
    (>>)         GHC.Base               m1 t1 -> m2 t2         -> m3 t3
    guard        Control.Monad          t1 -> m t2
    fmap         GHC.Base               forall a b. (a->b) -> n a -> n b
    mzip         Control.Monad.Zip      forall a b. m a -> m b -> m (a,b)

The comprehension should typecheck when its desugaring would typecheck,
except that (as discussed in :ref:`generalised-list-comprehensions`) in the
"then ``f``" and "then group using ``f``" clauses, when the "by ``b``" qualifier
is omitted, argument ``f`` should have a polymorphic type. In particular, "then
``Data.List.sort``" and "then group using ``Data.List.group``" are
insufficiently polymorphic.

Monad comprehensions support rebindable syntax
(:ref:`rebindable-syntax`). Without rebindable syntax, the operators
from the "standard binding" module are used; with rebindable syntax, the
operators are looked up in the current lexical scope. For example,
parallel comprehensions will be typechecked and desugared using whatever
"``mzip``" is in scope.

The rebindable operators must have the "Expected type" given in the
table above. These types are surprisingly general. For example, you can
use a bind operator with the type

::

    (>>=) :: T x y a -> (a -> T y z b) -> T x z b

In the case of transform comprehensions, notice that the groups are
parameterised over some arbitrary type ``n`` (provided it has an
``fmap``, as well as the comprehension being over an arbitrary monad.