utdemir
utdemir

Reputation: 27246

Confusion about IO and do notation

I'm a beginner in Haskell and confused about this code I wrote

readRecords :: String -> [Either String Record]
readRecords path = do
    f <- B.readFile path
    map parseLogLine (C8.lines f)

But it gives me this error:

Main.hs:15:10:
    Couldn't match type `IO' with `[]'
    Expected type: [C8.ByteString]
      Actual type: IO C8.ByteString
    In the return type of a call of `B.readFile'
    In a stmt of a 'do' block: f <- B.readFile path
    In the expression:
      do { f <- B.readFile path;
           map parseLogLine (C8.lines f) }

parseLogLine's type signature is parseLogLine :: B8.ByteString -> Either String Record.

I'm completely surprised. B.readFile path should return IO ByteString and so f should be ByteString. C8.lines f should return [ByteString] and map should return [Either String Record].

Where am I wrong?

Upvotes: 1

Views: 203

Answers (1)

Ganesh Sittampalam
Ganesh Sittampalam

Reputation: 29110

As a starting point, readRecords is defined with the wrong type. If the do block is to work in the IO monad, then it will produce an IO value, but you've defined it as returning [Either String Record] which is in the [] monad. That means that you can't call B.readFile which returns IO without triggering the type error you got.

Once you fix that, you'll find that the map expression on the last line of the do block has the wrong type because it produces [Either String Record] when it should produce IO [Either String Record]. Wrap the call in return to fix this.

Upvotes: 7

Related Questions