[Haskell-cafe] best practice for lifting of IO and could lifting be automated?

Oleg oleg at okmij.org
Mon Oct 26 11:03:32 UTC 2015

Dimitri DeFigueiredo wrote:

> Imagine I need to read a .CSV file which may or may not contain column
> titles on its first line. I'm not interested in the column titles, I
> just want the rest of the file. I am provided a library function to read
> the contents of the file (using a "callback"). The library author
> provided this function in the IO monad.

> withCSV :: FilePath -> (Handle -> IO r) -> IO r
> withCSV path action = do
>      putStrLn "opening file"
>      h <- openFile path ReadWriteMode
>      r <- action h
>      hClose h
>      putStrLn "file closed"
>      return r

> The problem arises because I also want to use the ReaderT monad
> transformer. My environment information will tell me
> whether or not to disregard the first (i.e. column title) line.

For this particular example, the answer is easy: If you have the IO
monads, you have the Reader monad, and the State/Writer as well. This
is just an IORef. 

> getFileContents :: IO String
> getFileContents = do
>   ref <- newIORef False
>   withCSV "data.csv" (myReadFile ref)
>      where
>          myReadFile :: IORef Bool -> Handle -> IO String
>          myReadFile ref handle = do
>              header <- readIORef ref -- ask --- OOOPPSss!!! FAIL! Can't ask.
>              case header of
>                  False      -> return ""
>                  True -> hGetLine handle -- skip first line
>              text <- hGetContents handle
>              return text

Using just IO, you can get State, Reader, Writer, and Exception (and
in a modular way!)

As to you general question, I will and do advocating abandoning monad
transformers altogether. The paper on extensible effects demonstrated
a new solution to the MonadCatchIO problem that solved the
long-standing issue of discarding state upon exception. See Sec 6 of


More information about the Haskell-Cafe mailing list