
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.