I'm creating a Conduit that will read binary files. Stuff can go wrong, so I need a monad with some error handling; for now Maybe
is good enough.
I'd like to use sourceFile
, which requires that the conduit monad be a MonadResource
, and this is the crux of the problem.
I see from the docs that e.g. MaybeT m
has an instance, but it requires m
to already be a MonadResource
; in fact this is true of all the instances. With my limited understanding this kinda sounds like a chicken-and-egg thing, requiring that I write a MonadResource
instance by hand no matter what?
I assume that to read files, my monad has to contain IO. So does all this mean that I have to write a MonadResource
instance for MaybeT IO
? If so, any pointers on how to do that?
A simple way is to use tryC
for example:
module Main (main) where
import Conduit
import Control.Exception (SomeException)
import qualified Control.Monad.Trans.Resource as R
import Data.Monoid ((<>))
import System.Environment (getArgs)
main :: IO ()
main = do
[fname] <- getArgs
r <- R.runResourceT . runConduit . tryC $ sourceFile fname .| await >>= pure
case r of
Left e -> putStrLn $ "Failed to read file content with " <> show (e :: SomeException)
Right r' -> putStrLn $ "File content: " <> show r'
Then you get:
[nix-shell:/tmp]$ ghc -Wall M.hs && ./M /tmp/doesnt_exist
[1 of 1] Compiling Main ( M.hs, M.o )
Linking M ...
Failed to read file content with /tmp/doesnt_exist: openBinaryFile: does not exist (No such file or directory)
[nix-shell:/tmp]$ ghc -Wall M.hs && ./M /tmp/hello-file
File content: Just "Hello world!