0

After getting help on an error where I used => rather than ->, I'm trying to implement distrib:

distrib :: (Monad m, Monad n) => n (m a) -> m (n a)
distrib x = do xx <- x
               return xx 

But, this does not work given the compile-time error:

Expected type: m (m a)
  Actual type: n (m a)

I realized that using do notation won't work since, when calling xx <- x, the expected return type (of the do block) is x, i.e. n (m a) - that's not what I want.

Please give me a hint on how to implement this function.

Community
  • 1
  • 1
Kevin Meredith
  • 41,036
  • 63
  • 209
  • 384
  • 11
    The type given has no implementation. For example, `IO (Maybe a) -> Maybe (IO a)` would allow us to find out some information about what an `IO` action returned without running it. You need to assume more about `m` and `n`. [This](http://stackoverflow.com/questions/7040844/applicatives-compose-monads-dont) might be an interesting thread. – luqui Apr 15 '15 at 19:39
  • Er wait I meant [this thread](http://stackoverflow.com/questions/29453915/composing-monads-v-applicative-functors/29454112#29454112) – luqui Apr 15 '15 at 19:43
  • 2
    See [Concrete example showing that monads are not closed under composition (with proof)?](http://stackoverflow.com/q/13034229/1333025). – Petr Apr 15 '15 at 19:52

1 Answers1

8

This function can't be written for two arbitrary monads, but it does exist when the outer type is Traversable, as some (but not all) Monad instances are:

sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)

You could then define

distrib :: (Monad m, Traversable m, Monad n) => m (n a) -> n (m a)
distrib = sequence

but this doesn't buy you anything, so you might as well just use sequence when appropriate.

Rein Henrichs
  • 15,437
  • 1
  • 45
  • 55