Version 1 (modified by Iceland_jack, 19 months 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.

## Related proposals

## 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 currently^{source}

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.

## Specification

*To be done''
*