Monad with MonadWriter Instance for Files

Is there a monad that wraps IO that has MonadWriter instance that uses the file for the writer state?

Like

newtype FileM w a = FileM (ReaderT Handle IO a) deriving (Functor, Applicative, Monad)

instance MonadWriter String (FileM String) where ...
instance MonadWriter Text (FileM Text) where ...
instance MonadWriter LazyByteString (FileM LazyByteString) where
  writer (x, w) = FileM $ ReaderT \h -> do
    BL.hPut h w
    return x
  listen m = FileM $ ReaderT \h -> do
    i <- hTell h
    x <- runFileM h m
    i' <- hTell h
    hSeek h AbsoluteSeek i
    w <- BL.hGet h $ fromInteger $ i' - i
    return (x, w)
  pass m = FileM $ ReaderT \h -> do
    i <- hTell h
    (x, f) <- runFileM @LazyByteString h m
    i' <- hTell h
    hSeek h AbsoluteSeek i
    w <- BL.hGet h $ fromInteger $ i' - i
    hSetFileSize h i
    hSeek h AbsoluteSeek i
    BL.hPutStr h $ f w
    return x

If not, is there a function like hGetContents but does not close the file handle when finished? I have an erroneous implementation here biparsing/biparsing-core/src/Control/Monad/HandleWriter.hs at f6e7f45704f71d654ca30c01fb52af5bcb1755b4 · BebeSparkelSparkel/biparsing · GitHub

2 Likes

You mean something like withFile? You can do all kinds of stuff to the file until you’re done with it.
(Also guarantees the handle is closed in case of exceptions/etc.)

Thanks pointing out that withFiles closes the handle upon error; I had not thought of that problem and have fixed a bug.

I have implemented a version for ByteString that I am trying to replicate for String and perhaps that will demonstrate what I am trying to accomplish. biparsing/biparsing-core/src/Control/Monad/FileM.hs at 9911cd428a6d9bc4d2a650ff2fa2f177856d538a · BebeSparkelSparkel/biparsing · GitHub

I think you’re going have to explain it, because I don’t really get what you’re trying to do.
Or at least, I don’t get why you’re trying to make a MonadWriter with a Handle in IO.

2 Likes

I have a lot of code that uses MonadWriter to abstract over the write types String, Text, and ByteString. Those are all in memory types, but I want to be able to use this existing code write to files. I could just write to the file from the in memory string but this option seems to have the potential to use less memory.