[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
http://okmij.org/ftp/Haskell/extensible/more.pdf
More information about the Haskell-Cafe
mailing list