Dannyu NDos
Dannyu NDos

Reputation: 2498

Is every repeatedly nested monads useful?

By the title, I mean types like Monad m => m (m a).

When the structure of a monad is simple, I can easily think of a usage of such type:

But it goes haywire in my mind if I think about the following types:

Is there a practical use for such types? Especially for the IO one?

On the second thought, I might need to randomly pick an IO action. That's an example of IO (IO a) which focuses on inputs. What about one focusing on outputs?

Upvotes: 5

Views: 214

Answers (2)

przemo_li
przemo_li

Reputation: 4053

Does not matter.

Monads are monads precisely because for every Monad ( Monad a ) we can always get Monad a. Such operation is called "join" and it's alternative operation to "bind" that could form definition of Monad. Haskell uses "bind" because its much more useful for composing monadic code :) (join can be implemented with bind, and bind with join - they are equivalent)

Does not matter

Is actually small lie, since ability to form Monad ( Monad a ) is also de facto part of what makes Monads monads. With Monad (Monad a) being transitional representation in some operations.

Full answer is: Yes, because that enables Monads. Though Monad ( Monad a ) can have extra "domain" meaning as you list for some of the Monads ;)

Upvotes: 0

chepner
chepner

Reputation: 530872

In some sense, a monad can be thought of as a functor in which layers can be collapsed.

If the Monad class were defined more like the category-theory definition, it would look like

class Applicative m => Monad m where
    return ::  a -> m a
    join :: m (m a) -> m a

Using fmap with a function of type a -> m b results in a function of type m a -> m (m b). join is used to eliminate one layer of monad from the result. Since that's a common thing to do, one might define a function that does it.

foo :: Monad m => (a -> m b) -> m a -> m b
foo f ma = join (fmap f ma)

If you look carefully, you'll recognize foo as >>= with its arguments flipped.

foo = flip (>>=)

Since >>= is used more than join would be, the typeclass definition is

class Applicative m => Monad m where
    return :: a -> m a
    (>>=) :: m a -> (a -> m b) -> m b

and join is defined as a separate function

join :: Monad m => m (m a) -> m a
join mma = mma >>= id

Upvotes: 2

Related Questions