how haskell catch throwIO called exception in ExceptT - haskell

when use monad transformer ExceptT to wrapper the IO Monad.
and then throwIO e in the inner IO monad,
so how this exception was catch by outer Exception and converted to and Either e a Type one
for example:
my program define type :
newtype HandlerT e a = HandlerT { runHandlerT :: ExceptT e (ReaderT (IO a)) }
then when in inner IO monad do the HTTP request to access and no-existen web site, the innert http.LBS will throw exception by call throwIO.
then ,
runExceptT $ runReaderT $ runHandlerT (http.LBS "http://notexist.com")
will return an Either e a
the e has the exception the inner call throw out.

You can use the safe-exceptions package (tutorial at: https://haskell-lang.org/library/safe-exceptions), which provides a set of functions which will help here in two ways:
They are lifted to work in many different monads, including ExceptT and ReaderT. Note that you will likely need to derive instances for MonadThrow and MonadCatch for your HandlerT.
You can use the catchAny and tryAny functions to catch all synchronous exceptions, which is probably what you want here. (See the linked tutorial for more information on synchronous vs asynchronous.)
That said: given that the httpLBS function is (most likely) living in IO itself, you can also do something like:
liftIO (tryAny (httpLBS req))
and avoid the need to bother with runtime exceptions in a monad transformer at all.

Related

Is Yesod's Handler Monad an instance of MonadBaseControl IO?

I would like to use the withResource :: MonadBaseControl IO m => Pool a -> (a -> m b) -> m b from the Data.Pool library in my handler code. I am trying to determine if Handler is an instance of MonadBaseControl IO, but I'm having a hard time finding the exact place that Handler is defined.
Is Yesod's Handler Monad (as created by mkYesodData) an instance of MonadBaseControl IO or can it easily be made into one?
No, Handler does not have a MonadBaseControl IO instance.
However, it's basically a reader, so it's not too difficult to write one.
Assuming you're using the scaffolded site, the following should work. Add some extensions and imports to the top of Foundation:
import Control.Monad.Base
import Control.Monad.Trans.Control
import Yesod.Core.Types (HandlerFor(..))
In some convenient place after the mkYesodData statement, add the instances:
instance MonadBase IO Handler where
liftBase = liftIO
instance MonadBaseControl IO Handler where
type StM Handler a = a
liftBaseWith ioAct = HandlerFor $ \handlerData ->
ioAct (\handlerAct -> unHandlerFor handlerAct handlerData)
restoreM = return
I have no idea if what you're generally trying to do is a good idea or not, but that should get things to type-check.

Dealing with IO exceptions inside the MonadError

I'm writing a function that queries a REST end-point to fetch some data, say queryServer:
queryServer :: (MonadIO m, MonadError Message m) => URL -> m String
The reason why I want to use the MonadError from Control.Monad.Except is that I want to have the short-circuiting behavior of this monad. So for instance it can be used as follows:
queryServers :: (MonadIO m, MonadError Message m) => m (String, String)
queryServers = do
res0 <- queryServer "server0"
res1 <- queryServer "server1"
return (res0, res1)
In this way, I do not have to worry about catching exceptions originated at queryServer and the function fails as soon as an error is encountered.
The problem I have with this approach (and there might be others I'm unaware of) is that I have to use some boilerplate to catch the IO exceptions and re-throw them with throwError:
queryServer url = do
result <- liftIO $ try (fetchSomething url)
case result of
Left (e :: IOException) -> throwError "error when fetching"
Right sth -> return sth
fetchSomething :: URL -> IO String
fetchSomething = undefined
I've seen several questions regarding the proper use of exceptions in Haskell, like this one, however none of them deals with the MonadError.
What is the right way to dealing with IO exceptions within the `MonadError?

What is the best way to manage resources in a monad stack like ExceptT a IO?

For better or for worse, Haskell's popular Servant library has made it common-place to run code in a monad transformer stack involving ExceptT err IO. Servant's own handler monad is ExceptT ServantErr IO. As many argue, this is a somewhat troublesome monad to work in since there are multiple ways for failure to unroll: 1) via normal exceptions from IO at the base, or 2) by returning Left.
As Ed Kmett's exceptions library helpfully clarifies:
Continuation-based monads, and stacks such as ErrorT e IO which provide for multiple failure modes, are invalid instances of this [MonadMask] class.
This is very inconvenient since MonadMask gives us access the helpful [polymorphic version of] bracket function for doing resource management (not leaking resources due to an exception, etc.). But in Servant's Handler monad we can't use it.
I'm not very familiar with it, but some people say that the solution is to use monad-control and it's many partner libraries like lifted-base and lifted-async to give your monad access to resource management tools like bracket (presumably this works for ExceptT err IO and friends as well?).
However, it seems that monad-control is losing favor in the community, yet I can't tell what the alternative would be. Even Snoyman's recent safe-exceptions library uses Kmett's exceptions library and avoids monad-control.
Can someone clarify the current story for people like me who are trying to plow our way into serious Haskell usage?
You could work in IO, return a value of type IO (Either ServantErr r) at the end and wrap it in ExceptT to make it fit the handler type. This would let you use bracket normally in IO. One problem with this approach is that you lose the "automatic error management" that ExceptT provides. That is, if you fail in the middle of the handler you'll have to perform an explicit pattern match on the Either and things like that.
The above is basically reimplementing the MonadTransControl instance for ExceptT, which is
instance MonadTransControl (ExceptT e) where
type StT (ExceptT e) a = Either e a
liftWith f = ExceptT $ liftM return $ f $ runExceptT
restoreT = ExceptT
monad-control works fine when lifting functions like bracket, but it has odd corner cases with functions like the following (taken from this blog post):
import Control.Monad.Trans.Control
callTwice :: IO a -> IO a
callTwice action = action >> action
callTwice' :: ExceptT () IO () -> ExceptT () IO ()
callTwice' = liftBaseOp_ callTwice
If we pass to callTwice' an action that prints something and fails immediately after
main :: IO ()
main = do
let printAndFail = lift (putStrLn "foo") >> throwE ()
runExceptT (callTwice' printAndFail) >>= print
It prints "foo" two times anyway, even if our intuition says that it should stop after the first execution of the action fails.
An alternative approach is to use the resourcet library and work in a ExceptT ServantErr (ResourceT IO) r monad. You would need to use resourcet functions like allocate instead of bracket, and adapt the monad at the end like:
import Control.Monad.Trans.Resource
import Control.Monad.Trans.Except
adapt :: ExceptT ServantErr (ResourceT IO) r -> ExceptT err IO r
adapt = ExceptT . runResourceT . runExceptT
or like:
import Control.Monad.Morph
adapt' :: ExceptT err (ResourceT IO) r -> ExceptT err IO r
adapt' = hoist runResourceT
My recommendation: have your code live in IO instead of ExceptT, and wrap each handler function in a ExceptT . try.

Inserting ErrorT at the base of transformer stack

What is the best way to run a code with type t (ErrorT String IO) a from within a t IO a monad? Consider the code below:
module Sample where
import System.IO
import Control.Monad.Reader
import Control.Monad.Error
type Env = String
inner :: ReaderT Env (ErrorT String IO) ()
inner = do
s <- ask
fail s
outer :: ReaderT Env IO ()
outer = do
env <- ask
res <- lift $ runErrorT $ runReaderT inner env
case res of
Left err -> liftIO $ hPutStrLn stderr err
Right _ -> return ()
outer
This works, but I've been looking for a more graceful way of inserting ErrorT at the base of my stack. Especially that I'm using several different monad transformer stacks in my project and writing the above for each of them is quite tedious.
I was looking for something like:
outer :: ReaderT Env IO ()
outer = do
res <- (hoist runErrorT) inner
...
But I cannot use hoist due to type mismatch.
Edit:
I use StateT in some of my stacks and that's the reason for trying to put ErrorT at the base and not on the top.
The outer is supposed to be an infinite loop.
Note that as Edward says, it would generally a lot simpler to put the ErrorT at the top of the stack, not the bottom.
This can change the semantics of the stack, at least for more complicated transformers than ReaderT - e.g. if you have StateT in the stack, then with ErrorT at the bottom changes to the state will be rolled back when there's an error, whereas with ErrorT at the top, changes to the state will be kept when there's an error.
If you do really need it at the bottom, then something like this passes the type checker:
import Control.Monad.Error
import Control.Monad.Morph
import System.IO
toOuter :: MFunctor t => t (ErrorT String IO) a -> t IO a
toOuter = hoist runErrorTWithPrint
runErrorTWithPrint :: ErrorT String IO a -> IO a
runErrorTWithPrint m = do
res <- runErrorT m
case res of
Left err -> do
hPutStrLn stderr err
fail err
Right v -> return v
Note that it calls fail when the inner computation fails, which isn't what your code above does.
The main reason is that to use hoist we need to provide a function of type forall a . ErrorT String IO a -> IO a - i.e. to handle any kind of value, not just (). This is because the depending on the rest of the monad stack might mean that the actual return type when you get to the ErrorT is different to the return type you started with.
In the failure case, we don't have a value of type a so one option is to fail.
In your original code you also loop infinitely in outer, which this doesn't do.
The right answer here is "don't do that".
The problem here is you're picking the layering. If you move the Error to the outside it'll behave properly for fail in this situation. In general view the transformer stack as some kind of quantum waveform you shouldn't collapse until the last minute.
inner :: MonadReader Env m => m ()
inner = do
s <- ask
fail s
outer :: (MonadReader Env m, MonadIO m) => m ()
outer = do
res <- runErrorT inner
case res of
Left err -> liftIO $ hPutStrLn stderr err
Right _ -> return ()
outer
Notice how much simpler everything gets. No hoisting, no explicit lifting, nada. inner is run in a different monad where we've extended our current monad whatever it is, with ErrorT on the outside.
By not picking the stack explicitly you maximize the number of situations in which you can use the code.
If you absolutely have to do it, then follow Ganesh's path, but think hard about whether you actually need to morph in the situation you described!

How to use ReaderT to transform Happstack's ServerPart Response?

This is the first time I'm playing with Monad Transformers. This is a simple happstack app.
{-# LANGUAGE OverloadedStrings #-}
import Happstack.Lite
import qualified Data.ByteString.Lazy.Char8 as L
main :: IO ()
main = do
serve Nothing hello
hello :: ServerPart Response
hello = do
ok $ toResponse ("Hello" :: L.ByteString)
I would like to be able to change hello so it can read some global config data using ReaderT. Let's just say the config is a string to keep it simple
type NewMonad = ReaderT L.ByteString (ServerPartT IO)
runNewMonad :: NewMonad a -> L.ByteString -> ServerPart a
runNewMonad k c = runReaderT k c
How do I change hello so it can use ask? I'm not sure what the type would be. NewMonad Response isn't quite right, because ok returns a ServerPart Response.
How do I change main so that serve works? It expects a ServerPart Response.
In fact, NewMonad Response is the correct type for hello; you just need to use lift to transform an action in the underlying monad to one in the transformer. For example:
hello :: NewMonad Response
hello = do
foo <- ask
lift . ok $ toResponse foo
In general,
lift :: (MonadTrans t, Monad m) => m a -> t m a
i.e., if you have a monadic action, then you turn it into an action in any monad transformer over that monad. This is the definition of a monad transformer: it can transform over any monad, and embed actions of that monad.
It seems that restricting all the monadic actions to one specific monad — rather than using typeclasses to work in any appropriate monad — is one of the simplifications happstack-lite uses compared to the full Happstack, which has this type for ok:
ok :: (FilterMonad Response m) => a -> m a
With this type, assuming appropriate instances are declared for the standard transformers, you could just use ok directly in MyMonad.
As for main, you need to eliminate the ReaderT layer, leading a a ServerPart Response that you can pass to serve:
main :: IO ()
main = do
serve Nothing $ runNewMonad hello ("Hello" :: L.ByteString)
(This would cause problems if you were using a monad carrying state that you wanted to change over the course of many requests, since serve's type is too restrictive to support such state threading (without manually encoding it with IORefs or similar); possibly the unrestricted Happstack has the ability to do this, but it'd likely be very brittle anyway, as you shouldn't really be relying on the order requests are processed in like that.)

Resources