-- | Prelude of proxies providing simple resource management features {-# LANGUAGE Rank2Types #-} module Control.Proxy.Safe.Prelude ( -- * Handle allocation withFile, -- * String I/O -- $string readFileS, writeFileD ) where import Control.Proxy (Proxy(request, respond), Producer) import Control.Proxy.Safe.Core (SafeIO, ExceptionP, bracket, tryIO) import qualified System.IO as IO -- | Safely allocate a 'IO.Handle' within a managed 'Proxy' withFile :: (Monad m, Proxy p) => (forall x . SafeIO x -> m x) -- ^Monad morphism -> FilePath -- ^File -> IO.IOMode -- ^IO Mode -> (IO.Handle -> ExceptionP p a' a b' b m r) -- ^Continuation -> ExceptionP p a' a b' b m r withFile morph file ioMode = bracket morph (IO.openFile file ioMode) IO.hClose {- $string Note that 'String's are very inefficient, and I will release future separate packages with 'ByteString' and 'Text' operations. I only provide these to allow users to test simple I/O without requiring any additional library dependencies. -} {-| Read from a file, lazily opening the 'IO.Handle' and automatically closing it afterwards -} readFileS :: (Proxy p) => FilePath -> () -> Producer (ExceptionP p) String SafeIO () readFileS file () = withFile id file IO.ReadMode $ \handle -> do let go = do eof <- tryIO $ IO.hIsEOF handle if eof then return () else do str <- tryIO $ IO.hGetLine handle respond str go go {-| Write to a file, lazily opening the 'IO.Handle' and automatically closing it afterwards -} writeFileD :: (Proxy p) => FilePath -> x -> ExceptionP p x String x String SafeIO r writeFileD file x0 = do withFile id file IO.WriteMode $ \handle -> do let go x = do str <- request x tryIO $ IO.hPutStrLn handle str x2 <- respond str go x2 go x0