Version 1 (modified by Iceland_jack, 4 years ago) (diff)

--

# Generalized monad comprehensions

This is a proposal to generalize MonadComprehensions (in conjunction with the `ParallelListComp` and `TransformListComp` extensions) from ticket #8914 as well as do-notation.

## Motivation

A `Monad` constraint is sometimes too powerful both with with `MonadComprehensions` extension and using do-notation.

### Functor

Ideally the following functions could be desugared into `fmap` with a `Functor` constraint:

```{-# LANGUAGE MonadComprehensions #-}

fmapM :: Functor f => (a -> b) -> f a -> f b
fmapM f xs = [ f x | x <- xs ]

fmapDo :: Functor f => (a -> b) -> f a -> f b
fmapDo f xs = do
x <- xs
return (f x)
```

but their inferred signatures are `Monad m => (a -> b) -> m a -> m b`.

### Applicative functor

The following are equivalent to, and could be safely replaced with, `liftA3`:

```threeM :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d
threeM f a1 a2 a3 = [ f x1 x2 x3 | x1 <- a1, x2 <- a2, x3 <- a3 ]

threeDo :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d
threeDo f a1 a2 a3 = do
x1 <- a1
x2 <- a2
x3 <- a3
return (f x1 x2 x3)
```

but get a more restricted `Monad` constraint.

### MonadZip

`MonadZip` (from Control.Monad.Zip) is a type class that requires a `Monad` constraint but could make do with a `Functor` constraint (or possibly no constraint at all but then the default implementations could not be implemented and the laws could not be expressed. The definition is currentlysource

```class Monad m => MonadZip m where
mzip :: m a -> m b -> m (a,b)
mzip = mzipWith (,)

mzipWith :: (a -> b -> c) -> m a -> m b -> m c
mzipWith f ma mb = liftM (uncurry f) (mzip ma mb)

munzip :: m (a,b) -> (m a, m b)
munzip mab = (liftM fst mab, liftM snd mab)
```

but could be

```class Functor f => FunctorZip f where
fzip :: f a -> f b -> f (a,b)
fzip = fzipWith (,)

fzipWith :: (a -> b -> c) -> f a -> f b -> f c
fzipWith f fa fb = fmap (uncurry f) (fzip fa fb)

funzip :: f (a,b) -> (f a, f b)
funzip fab = (fmap fst fab, fmap snd fab)
```

I noticed this in particular when I wanted to use length-indexed lists with a monad comprehension using only the (trivially defined) `Applicative` and `FunctorZip` instances, but was forced to define the `Monad` instance that was of no use for my particular case.

To be done''