# 6.2.8. Monad comprehensions¶

- MonadComprehensions¶
- Since:
7.2.1

Enable list comprehension syntax for arbitrary monads.

Monad comprehensions generalise the list comprehension notation, including parallel comprehensions (Parallel List Comprehensions) and transform comprehensions (Generalised (SQL-like) 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

`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

`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

`ParallelListComp`

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

Parallel statements are translated using the

`mzip`

function, which requires a`MonadZip`

instance defined in 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 `MonadComprehensions`

extension is enabled. The types and more detailed examples on how to use
comprehensions are explained in the previous chapters
Generalised (SQL-like) List Comprehensions and
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 `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]`

:

```
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 Generalised (SQL-like) 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
(Rebindable syntax and the implicit Prelude import). 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.