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

Oleg oleg at okmij.org
Mon Oct 26 13:55:22 UTC 2015

Roman Cheplyaka wrote:
> Not really. You are passing 'ref' into myReadFile by hand here. If you
> are willing to pass parameters by hand, there is no need in IORef at
> all; you could just as well pass header directly.

I confess in embellishing the problem and tacitly upgrading Reader to
the State. The original problem seemed too simple. In penance, I show
the solution to the original problem, using exactly the signature of
the original poster, and using exactly his code for myReadFile,
(but with the lifted type, which is what he wanted, it seems).

> data ColumnHeaders = FirstLine | None
> getFileContents :: ReaderT ColumnHeaders IO String
> getFileContents = do
>   header <- ask -- can ask it here
>   lift $ withCSV "data.csv" (\handle -> runReaderT (myReadFile handle) header)
>      where

> myReadFile :: Handle -> ReaderT ColumnHeaders IO String
> myReadFile handle = do
>   header <- ask   -- Now, we can ask it, alright
>   case header of
>     None      -> return ""
>     FirstLine -> lift $ hGetLine handle -- skip first line
>   text <- lift $ hGetContents handle
>   return text

The idea is simple: since withCSV wants its callback to be IO rather
than ReaderT IO, it means the withCSV is not capable of altering the
environment of the callback. Therefore, the myReadFile is executed in
the same environment, regardless of the Handle. Once we understand
this, the solution is trivial.

So, to answer the question of the original poster: it seems we can do
what he wants withCSV he got. There is no need to ask withCSV author
for anything.

> I agree that *given a ReaderT* (or implicit params, or your implicit
> configurations), you can emulate StateT/WriterT using IORefs (but only
> one way of stacking w.r.t. exceptions).

Actually, it is easy to get other ways of `stacking with respect to
exceptions.' Once we get persistent state (which is what IORef
provide), we can always discard that state by writing an appropriate
exception handler. I guess I can make another stab at monad
transformers and say that thinking in terms of stacks is not always

More information about the Haskell-Cafe mailing list