Kevin Meredith
Kevin Meredith

Reputation: 41939

IO Monad Example

Consider the following IO code:

ghci> let x = return 100 :: IO Int

ghci> :t do { a <- x; print a; return 500 }
do { a <- x; print a; return 500 } :: Num b => IO b

My understanding of do notation/bind is that the following signature will be enforced by the compiler:

ghci> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b

In the above example, my understanding is:

It seems to me that IO () does not conform to the type, Num b => IO b. Additionally, IO Int does not conform to Num b => IO b, as I understand.

If this observation is valid, then why does this code compile? Must not each line, i.e. >>=, conform to m b, where m equals IO and b equals Num b => b?

Upvotes: 0

Views: 113

Answers (2)

Alec
Alec

Reputation: 32329

The code you posted desugars into the following.

x >>= (\a ->
print a >>
return 500)

Or, expanding out the definition of (>>)

x       >>= (\a ->
print a >>= (\_ ->
return 500))

Then, you can see that in the different calls to (>>=), the types a and b are not necessarily the same. Say (>>=) :: Monad m => m a -> (a -> m b) -> m b.

  • in the first call: x has type IO Int, \a -> print a >>= (\_ -> return 500) has type Num c => Int -> IO c, so the a in our type signature for (>>=) is Int, and the b is c (with the Num restriction).

  • in the second call: print a has type IO (), and \_ -> return 500 has type Num c => () -> IO c (the () part is inferred from trying to match the signature of (>>=)) so the a in our type signature for (>>=) is (), and the b is c (still with the Num restriction).

Upvotes: 3

shree.pat18
shree.pat18

Reputation: 21757

do { a <- x; print a; return 500 } is equivalent to (return 100 :: Int) >>= print >> return 500.

The signature for >> is (>>) :: Monad m => m a -> m b -> m b, which is in sync with what is seen.

Upvotes: 1

Related Questions