Can a custom guard mechanism be defined in Haskell? - haskell

If you look at the example for catches:
f = expr `catches` [Handler (\ (ex :: ArithException) -> handleArith ex),
Handler (\ (ex :: IOException) -> handleIO ex)]
It looks like catches has defined a custom mechanism to match on patterns (the two exception types). Am I mistaken, or can this be generalized to allow one to define a function that can take lambda functions that match on a certain pattern?
Edit: FYI below is the GHC source for catches. If someone can shed some light on how this works it would be great.
catches :: IO a -> [Handler a] -> IO a
catches io handlers = io `catch` catchesHandler handlers
catchesHandler :: [Handler a] -> SomeException -> IO a
catchesHandler handlers e = foldr tryHandler (throw e) handlers
where tryHandler (Handler handler) res
= case fromException e of
Just e' -> handler e'
Nothing -> res

This is the Scoped Type Variables GHC extension at work. Follow the link to learn more.
Basically, you define an assertion about type that have to be met by the patter before it can match. So, yeah, it is akin to guards, but not completely so.
How this particular example works? Dive into sources of "base" library to find out that:
class (Show e) => Exception e where
toException :: e -> SomeException
fromException :: SomeException -> Maybe e
data SomeException = forall e . Exception e => SomeException e
instance Exception IOException where
toException = IOException
fromException (IOException e) = Just e
fromException _ = Nothing
instance Exception ArithException where
toException = ArithException
fromException (ArithException e) = Just e
fromException _ = Nothing
We see that IOException and ArithException are different types implementing the typeclass Exception. We also see that toException/fromException is a wrapping/unwrapping mechanism that allows one to convert values of type Exception to/from values of types IOException, ArithException, etc.
So, we could've written:
f = expr `catches` [Handler handleArith,
Handler handleIO]
handleArith :: ArithException -> IO ()
handleArith ex = ....
handleIO :: IOException -> IO ()
handleIO ex = ....
Suppose that IOException happens. When catchesHandler processes first element of the handlers list, it calls tryHandler, which calls fromException. From the definition of tryHandler it follows that return type of the fromException should be the same as argument of handleArith. On the other hand, e is of type Exception, namely - (IOException ...). So, the types play out this way (this is not a valid haskell, but I hope that you get my point):
fromException :: (IOException ...) -> Maybe ArithException
From the instance Exception IOException ... it follows immediately that the result is Nothing, so this handler is skipped. By the same reasoning the following handler would be called, because fromException would return (Just (IOException ...)).
So, you've used type signatures of handleArith and handleIO to specify when each of them would be called, and fromException/toException made sure that it happened this way.
If you want to, you could also constraint types of handleIO and handleArith inside the definition of f, using scoped type variables. Arguably, this could give you better readability.
Finalizing, Scoped Type Variables are not a primary players here. They are just used for convenience. Main machinery for playing this kind of tricks is fromException/toException and friends. Scoped Type Variables just allow you to have syntax which more closely resemble guard patterns.

case () of
()| foo expr1 -> handleFooCase
| bar expr2 -> handleBarCase
| otherwise -> blah

Related

What is difference between normal functions and typeclass functions?

class (Typeable e, Show e) => Exception e where
toException :: e -> SomeException
fromException :: SomeException -> Maybe e
toException = SomeException
fromException (SomeException e) = cast e
data MyException1 = Exception1A | Exception1B
deriving (Show)
instance Exception MyException1
data MyException2 = Exception2A | Exception2B
deriving (Show)
instance Exception MyException2
It is able to define multiple exceptions. So, multiple fromException functions are able to be defined too. I think it is weird because two functions can have same name and same input.
fromException :: SomeException -> Maybe MyException1
fromException :: SomeException -> Maybe MyException2
Even if the reason why this behavior is ok is "Two functions have different type include return type (and expressions are evaluated based these all types)", it is weird, because I can't define normal functions that way.
f :: Integer -> Maybe Integer
f = cast
f :: Integer -> Maybe Char
f n = cast $ show n
What is difference between normal functions and type class functions?
The fact that you cannot define normal functions that way is the whole difference.
The whole purpose of type classes is to allow overloading - that is, defining multiple different functions with different types, but same name. And have the compiler pick the right one automatically based on types expected in the context.

How to use Handlers that don't have SomeException as their argument type

When using Control.Monad.Throw (i.e. exceptions package), something that confuses me that it seem that all my my throwing and catching has to work with SomeException.
E.g.
value :: Either ExitCode String
value = throwM $ ExitFailure 23
This looks to me like it should compile, because throwM :: (Exception e, MonadThrow m) => e -> m a, and ExitCode has an instance of Exception. Even this doesn't compile:
value :: Exception e => Either e String
value = throwM $ ExitFailure 23
In fact, it only compiles when I change the signature to SomeException. I know the Exception type class has a special place re
In the documentation for Control.Exception I could see examples where they use catches with handlers of signature ArithException -> m a or similiar. I tested it and it worked.
Is this not possible when using exceptions?
EDIT
The error messages are either:
Couldn't match type ExitCode with SomeException arising from a use of throwM
or
Couldn't match type e with SomeException arising from a use of throwM
The behavior you are seeing is from the type signature of throwM:
throwM :: (Exception e, MonadThrow m) => e -> m a
And the instance for Either, which is essentially:
MonadThrow (Either SomeException)
This makes throwM:
throwM :: (Exception e) => e -> Either SomeException a
throwM for Either SomeException can take any Exception e.
However, there is no MonadThrow instance for Either ExitCode, or for forall e. Exception e => Either e.
The problem is that there isn't really a way to write an instance that's polymorphic for all e. Imagine having an instance
Exception q => MonadThrow (Either q)
This would make throwM:
throwM :: (Exception e, Exception q) => e -> Either q a
which means you have to be able to take any e and convert it into any q, which is not possible using the Exception typeclass alone.
Imagine also if there was a MonadThrow instance for Either ExitCode. That would make the type signature for throwM:
throwM :: Exeption e => e -> Either ExitCode a
which you can probably see is clearly nonsensical, since there are many instances of Exception that cannot be coerced to an ExitCode. (Try writing a function with that type signature if you don't believe me!)
If you just want short-circuting exception behavior for Either, consider:
Just use Left instead of throwM, and pattern matching for catch. If you really want to use Exception still, you can use fromException to attempt to coerce a SomeException into an Exception instance of your choice.
You can use the exceptions package, and catching will still work as long as you must assume that the exception could be any instance (SomeException)
Use MonadError and ExceptT from mtl, if you want some sort of polymorphic interface with catching ability

GHC try-catch for runStmt/exprType

GHC monad is an instance of ExceptionMonad and there are the two actions runStmt and exprType that interest me currently. Should one pass an invalid argument (e.g. an undefined symbol, syntactically incorrect string ...) any of the two would raise an exception, effectively terminating the session (in interpreter mode). How could one wrap these functions so that they always succeed, but produce a Maybe or Either result to account for exceptions? One thing I don't understand is, why does runStmt also throw an exception when it already supports returning one in its return value. For exprType I am seeking something like
exprType' :: GhcMonad m => String -> m (Maybe Type)
exprType' e = (fmap Just $ exprType e) `catch` (const $ return Nothing)
I am currently using GHC 7.10.2, and I am really confused with all Either/Error/... implementations of exceptional behaviour, so I do not have any piece of code that would be anywhere close to my goal :(.
The closest I got is (I try to convert the Either further to a single string, which should not be important):
typeOf :: String -> Ghc String
typeOf e = do
r <- gtry (exprType e)
return . either (const "err") (showSDocUnsafe . ppr) $ r
but then ghc complains:
No instance for (Exception b0) arising from a use of ‘gtry’
The type variable ‘b0’ is ambiguous
Note: there are several potential instances:
instance Exception ArithException -- Defined in ‘GHC.Exception’
instance Exception ErrorCall -- Defined in ‘GHC.Exception’
instance Exception SomeException -- Defined in ‘GHC.Exception’
...plus two others
In the first argument of ‘(>>=)’, namely ‘gtry (exprType e)’
In the expression:
gtry (exprType e)
>>= return . either (const "err") (showSDocUnsafe . ppr)
In an equation for ‘typeOf’:
typeOf e
= gtry (exprType e)
>>= return . either (const "err") (showSDocUnsafe . ppr)

Parameterising Partial Functions By Error Type

I have a situation in which the majority of the operations I am using are partial functions. I want the return type of the functions to vary depending on the context, which should determine the kind of exception handling that occurs, and the type of errors that are reported. My current solution is to define a function parameterised by an error type, then implement the operation as an open function using type classes. For example, the following is an implementation of head, assuming a suitable implementation of Error and MonadError for Maybe in terms of the unit type:
class (Error e, MonadError e m) => Head m e | m -> e where
head :: [a] -> m a
errorHead :: (Error e, MonadError e m) => e -> [a] -> m a
errorHead e [] = throwError e
errorHead e (x : xs) = return x
instance Head Maybe () where
head = errorHead ()
instance Head (Either String) String where
head = errorHead "error: empty list"
The advantage of this implementation is that different errors can be thrown depending on the context in which head is called. The question I have is whether this can be accomplished without defining the function using an auxiliary operation and open functions. If not, the second question is whether this solution is optimal. In particular, is there a better way to achieve this behavior?
The http://hackage.haskell.org/package/errors package has many utilities for moving between Maybe, Either, MaybeT, and EitherT.

Could not deduce type

I am attempting to pattern match on a type in a case statement such as the following:
result <- action
case result of
Success _ -> do something
Failure e -> case e of
MyException myField -> do take another action
_ -> ...
The compiler can't deduce e ~ MyException which I understand. My question is what other information do I need to supply to the compiler to be able to match my exception type. In this particular case I know that if there is a Failure the returned type will be MyException.
EDIT:
The type of result (From the Aws package) is:
(Transaction r a, ConfigurationFetch (Info r)) =>
Configuration -> r -> IO (Response (ResponseMetadata a) a)
a is from Data.Attempt which is either a Success or Failure.
Assuming you're using extensible exceptions (which is the default in recent ghc's), your result is probably something like
data Result = Success MySuccess | Failure SomeException
You need to convert the SomeException to your own exception type. This is done with the function toException :: Exception e => SomeException -> Maybe e. Then you would handle this like:
Failure e -> case toException e of
Just (MyException myField) -> do take another action
_ -> ...
Of course this is assuming that I'm right about your Result type.

Resources