Hi there, after a while, I’ve started studying Haskell again and now I’m on exception part
And my question is following: why if I do fromException with SomeException or ArithException I get the same answer "Just divide by zero"
x = toException DivideByZero
fromException @ArithException x -- Just divide by zero
fromException @SomeException x -- Just divide by zero
but if I write directly the same one code, I get Nothing with SomeException
x = toException DivideByZero
f :: Exception e => SomeException -> Maybe e
f = \ (SomeException e) -> cast e
f @ArithException x -- Just divide by zero
f @SomeException x -- Nothing
here are definitions
fromException :: Exception e => SomeException -> Maybe e
fromException (SomeException e) = cast e
f :: Exception e => SomeException -> Maybe e
f = \ (SomeException e) -> cast e
maybe I missed something? but I’m truly can’t understand why is that
fromException :: Exception e => SomeException -> Maybe e is a method from the Exception typeclass. So the actual implementation is determined by the concrete type of e, the type into which we want to convert the SomeException argument.
fromException @ArithException will use the instance for ArithException, and fromException @SomeException will use the instance for SomeException.
The instance method for ArithException is much like your f function (it’s not immediately clear because it’s inherited from the default implementation for Exception).
However, the method for SomeException is much unlike f! It’s actually
instance Exception SomeException where
fromException = Just
Why? Because a conversion from SomeException into SomeException is trivial and never fails. So we simply return the input SomeException wrapped in Just.
casting the contents of the SomeException like f tries to do won’t work in this case, because the value inside the SomeException is actually the ArithException! The cast will fail. SomeException is an (existentially quantified) wrapper.