These are type variables with the scope of the GHC extension at work. Follow the link to find out more.
Basically, you define a type assertion that must be done with patter before it can match. So yes, thatβs akin to the guards, but not completely.
How does this specific example work? Immerse yourself in the sources of the "base" library to find out what:
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 that implement typeclass Exception . We also see that toException/fromException is a wrapping / deployment mechanism that allows you to convert values ββof type Exception to / from values ββof types IOException , ArithException , etc.
So, we could write:
f = expr `catches` [Handler handleArith, Handler handleIO] handleArith :: ArithException -> IO () handleArith ex = .... handleIO :: IOException -> IO () handleIO ex = ....
Assume that an IOException occurring. When catchesHandler processes the first element of the list of handlers, it raises a tryHandler , which raises fromException . From the definition of tryHandler it follows that the return type fromException must match the handleArith argument. On the other hand, e is of type Exception, namely - (IOException ...). So, types are played out this way (this is not a valid haskell, but I hope you get my thought):
fromException :: (IOException ...) -> Maybe ArithException
From the instance Exception IOException ... immediately follows that the result is Nothing , therefore this handler is skipped. For the same reasons, the next handler will be called because fromException will return (Just (IOException ...)) .
So, you used handleArith and handleIO type signatures to indicate when each would be called, and fromException/toException made sure that it happened.
If you want, you can also restrict the types of handleIO and handleArith inside the definition of f using variables of type region. Perhaps this may give you better readability.
Lastly, scope type variables are not the main players here. They are just used for convenience. The main technique for playing tricks is fromException/toException and friends. The copied type variables allow you to have syntax that more closely resembles security patterns.