tags:

views:

102

answers:

2

Hi

I was trying some code segment from one of the blog and I came to notice the following code

f :: Int -> [Int]
f x = [1+x,2*x]

test :: IO ()
test = putStrLn . show $ return 5 >>= f >>= f

While executing I am getting [7,12,11,20]. Why the second 'f' function call is not throwing type error ? Is it something related to List Monad?

+6  A: 

It is exactly because lists are monads. You have

return 5 >>= f >>= f

In the list monad, (>>=) = flip concatMap, so that's the same as

concatMap f $ concatMap f $ return 5

Also in the list monad, return x = [x], so we have

concatMap f $ concatMap f [5]

Now, concatMap g x = concat (map g x), so we can expand that to

concat $ map f $ concat $ map f [5]

and evaluate it

concat $ map f $ concat $ [[6, 10]]
concat $ map f $ [6, 10]
concat $ [[7, 12], [11, 20]]
[7, 12, 11, 20]

Does that make sense?

Dave Hinton
Thanks. I got confused with a <- return 5 and let a = 5
jijesh
+4  A: 

Let's ask GHC what the types are for some of the subexpressions.

> :t putStrLn . show
putStrLn . show :: (Show a) => a -> IO ()

That's certainly as expected.

> :t return 5 >>= f >>= f
return 5 >>= f >>= f :: [Int]

I suppose we expected that, but it doesn't answer your question. Next, a quick reminder on how that expression parses:

> :i (>>=)
class Monad m where
  (>>=) :: m a -> (a -> m b) -> m b
  ...
infixl 1 >>=

Okay, it's left associative, so the expression is (return 5 >>= f) >>= f.

> :t return 5 >>= f
return 5 >>= f :: [Int]

Comparing this to the above type signature for (>>=), we can observe two things:

  • The second argument of (>>=) must return some sort of monad
  • The first argument of (>>=) must be a value in the same monad

So we know that f has to have a type shaped like (a -> m b) here, and the actual type signature for f is Int -> [Int]. So we can manually combine the types:

  • a = Int
  • b = Int
  • m = []

Note that ([] a) means the same thing as [a].

So the monad is indeed the list monad. So what's going on?

> return 5 :: ([] Int)
[5]
> [5] >>= f
[6, 10]
> ([5] >>= f) >>= f
[7, 12, 11, 20]
camccann
Thanks for the answer . Now I understood how it works. looks like there is lot to learn about monads
jijesh