Thanks for the excellent explanation! :

On Fri, Jun 10, 2011 at 4:49 PM, Daniel Fischer <daniel.is.fischer@googlemail.com> wrote:
On Friday 10 June 2011, 14:25:59, Dmitri O.Kondratiev wrote:
> Two questions:
> 1) Why to use 'fmap' at all if a complete file is read in a single line
> of text?

Well, it's a matter of taste whether to write

   foo <- fmap read (readFile "bar")
   stuffWithFoo

or

   text <- readFile "bar"
   let foo = read text
   stuffWithFoo

The former saves one line of code (big deal).

>
> 2) Trying to use 'fmap' illustrates 1) producing an error (see below):
> main = do
>      let xss = [[1,2,3],[4,5,6],[7,8],[9]]
>      writeFile "output.txt" (show xss)
>      xss2 <- fmap read (readFile "output.txt") :: [[Int]]

That type signature doesn't refer to xss2, but to the action to the right
of the "<-", `fmap read (readFile "output.txt")'

readFile "output.txt" :: IO String

so

fmap foo (readFile "output.txt") :: IO bar

supposing

foo :: String -> bar

You want read at the type `String -> [[Int]]', so the signature has to be

   xss2 <- fmap read (readFile "output.txt") :: IO [[Int]]

>      print xss2
>
> == Error:
>  Couldn't match expected type `[String]'
>              with actual type `IO String'
>  In the return type of a call of `readFile'
>  In the second argument of `fmap', namely `(readFile "output.txt")'
>  In a stmt of a 'do' expression:
>      xss2 <- fmap read (readFile "output.txt") :: [[Int]]

Looking at the line

   xss2 <- fmap read someStuff :: [[Int]]

the compiler sees that

fmap read someStuff should have type [[Int]]

Now, fmap :: Functor f => (a -> b) -> f a -> f b

and [] is a Functor, so the fmap here is map, hence

map read someStuff :: [[Int]]

means

someStuff :: [String]

That's the expected type of (readFile "output.txt"), but the actual type is
of course IO String, which is the reported error.