4

I'm trying to understand (>>=).(>>=), which GHCi tells me is:

(>>=)       :: Monad m => m a -> (a -> m b) -> m b
(>>=).(>>=) :: Monad m => m a -> (m b -> (a -> m b) -> b1) -> (a -> m b) -> b1

can you provide a step by step explanation on how the result is derived?

And is this composition ever used?

Update:

I am able to work out fmap.fmap but not quit (>>=).(>>=), I'm able to get to (.)(>>=) :: Monad m => (a1 -> m a) -> a1 -> (a -> m b) -> m b but afterword things start to get a little confusing. Any help would be appreciated, just trying to learn here.

  • 5
    Have you tried deriving it yourself? Where did you get stuck? There are many questions already on Stack Overflow that show step by step how to derive types, such as [How (fmap . fmap) typechecks](//stackoverflow.com/q/23030638) – 4castle Feb 02 '18 at 00:24
  • 4
    The return value should be `b1`, not `b`. – chepner Feb 02 '18 at 00:52
  • 1
    How is this a duplicate of that? – dfeuer Feb 02 '18 at 04:22
  • 1
    @dfeuer It's not. It's only ___similar___. – Zeta Feb 02 '18 at 07:07
  • @Zeta, I don't even see much similarity. This one seems tied to `Monad ((->) a)`, for one thing. `fmap . fmap`, `foldMap . foldMap`, and `traverse . traverse` are all similar to each other, but this seems quite different. – dfeuer Feb 02 '18 at 07:36
  • 1
    @dfeuer that's because `(>>=)` takes a function as its second argument, if we use the flipped version instead (which like `fmap`, `traverse`, `foldMap` maps a function to a function) `(=<<) :: Monad m => (a -> m b) -> m a -> m b` we get the following `(=<<) . (=<<) :: Monad m => (a -> m b) -> m (m a) -> m b` which is quite similar to `fmap . fmap` or `traverse . traverse`. Also notice that `((=<<) . (=<<)) return = join`. In fact `(=<<) . (=<<)` is very similar to `foldMap . foldMap` – Mor A. Feb 02 '18 at 13:07

1 Answers1

10

TL;DR: We use the ((->) r monad instance inbetween.


We have to look at (.) (>>=). So let us first repeat the types:

(>>=) :: Monad m => m a -> ((a -> m b) -> m b)
(.)   ::            (y  -> z                 ) -> (x -> y) -> (x -> z)

Therefore, we have

(.) (>>=) :: Monad m => (x -> m a) -> (x -> ((a -> m b) -> m b))
-- or, with less parentheses
(.) (>>=) :: Monad m => (x -> m a) -> x -> (a -> m b) -> m b

Now, we plug in another (>>=):

(.) (>>=) :: Monad m => (x ->  m a               ) -> x -> (a -> m b) -> m b
(>>=)     :: Monad k => k i -> ((i -> k j) -> k j)

But now we have a problem. We have Monad m => m a and ((i -> k j) -> k j) at the same position. Is that even possible? Well, it's possible if there is a monad instance for

Monad k => (->) (i -> k j)

Turns out there is one, namely

instance Monad ((->) r)

for any r. Now our outer monad m is ((->) (i -> k j), therefore we replace all occurences of m by (i -> k j) ->:

(.) (>>=) ::             (x -> (i -> k j) -> a) -> x -> (a -> (i -> k j) -> b) -> (i -> k j) -> b
(>>=)     :: Monad k => k i -> ((i -> k j) -> k j)

Now set x ~ k i, a ~ k j and we end up with

(.) (>>=) ::             (x -> (i -> k j) -> a) -> x -> (a -> (i -> k j) -> b) -> (i -> k j) -> b
(>>=)         :: Monad k => k i -> ((i -> k j) -> k j)
(>>=) . (>>=) :: Monad k => k i -> (k j -> (i -> k j) -> b) -> (i -> k j) -> b

Last, we rename k to m, i to a and j to b2, and we end up with

(>>=) . (>>=) :: Monad m => m a -> (m b2 -> (a -> m b2) -> b) -> (a -> m b2) -> b
Zeta
  • 103,620
  • 13
  • 194
  • 236