Reputation: 2498
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:
[[a]]
, which is a multidimensional list
Maybe (Maybe a)
, which is a type adjoined by two error states
Either e (Either e a)
, which is like above, but with messages
Monoid m => (m,(m,a))
, which is a writer monad with two things to write over
r -> r -> a
, which is a reader monad with two things to read from
Identity (Identity a)
, which is still the identity monad
Complex (Complex a)
, which is a 2-by-2 matrix
But it goes haywire in my mind if I think about the following types:
ReadP (ReadP a)
? Why would it be useful when ReadP
isn't an instance of Read
?
ReadPrec (ReadPrec a)
? Like above?
Monad m => Kleisli m a (Kleisli m a b)
?
IO (IO a)
!? This must be useful. It just is too hard to think about it.
forall s. ST s (ST s a)
!? This should be like the above.
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
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
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