
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.