3
votes

I'm learning Haskell and I'm trying to figure out why I'm getting an error on the following piece of code. I'm trying to define a function that can read a file at a given location, and perform some function on it, but it has an error that I'm afraid I can't get my head around.

I imagine I'm doing something stupid but I can't figure out what; can someone tell me?

readAndProcessFile ::  String -> (String -> a) -> a
readAndProcessFile l f = do
    contents <- readFile l -- error here
    let result = f contents
    return result

I get the error:


Occurs check: cannot construct the infinite type: a ~ IO a

In a stmt of a 'do' block: contents <- readFile l

In the expression:

do contents <- readFile l
   let result = (f contents)
   return result

In an equation for ‘readAndProcessFile’:

  readAndProcessFile l f
    = do contents <- readFile l
         let result = ...
         return result

• Relevant bindings include

f :: String -> a
readAndProcessFile :: String -> (String -> a) -> a

1
the type of readAndProcessFIle is String -> (String -> a) -> IO a.Willem Van Onsem
That's very useful, thanks - am I right in thinking that there's no way to have this return a instead of IO a?OliverRadini
@OliverRadini: well the idea of IO is exactly to add a layer to make this impossible (well you can use unsafePerformIO, but that is, like the name suggests, unsafe).Willem Van Onsem
@WillemVanOnsem Understood - appreciate the help!OliverRadini

1 Answers

5
votes

the type of readAndProcessFile is String -> (String -> a) -> IO a. Indeed, you use a do block, so that means it is monadic. What you here basically write is readFile >>= \contents -> let result = f contents in return result. The readFile furthermore specializes this to an IO.

You can simplify the expression by making use of <$> :: Functor f => (a -> b) -> f a -> f b

readAndProcessFile :: FilePath -> (String -> a) -> IO a
readAndProcessFile l f = f <$> readFile l