Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/parsonsmatt/exception-via

Derive hierarchical exception instances for your datatypes
https://github.com/parsonsmatt/exception-via

Last synced: 10 days ago
JSON representation

Derive hierarchical exception instances for your datatypes

Awesome Lists containing this project

README

        

# exception-via

Haskell supports hierarchical exceptions, but there's a bit of boilerplate involved.
The [documentation for `Control.Exception`](https://www.stackage.org/haddock/lts-16.20/base-4.13.0.0/Control-Exception.html#t:Exception) has a write-up:

```haskell
---------------------------------------------------------------------
-- Make the root exception type for all the exceptions in a compiler

data SomeCompilerException = forall e . Exception e => SomeCompilerException e

instance Show SomeCompilerException where
show (SomeCompilerException e) = show e

instance Exception SomeCompilerException

compilerExceptionToException :: Exception e => e -> SomeException
compilerExceptionToException = toException . SomeCompilerException

compilerExceptionFromException :: Exception e => SomeException -> Maybe e
compilerExceptionFromException x = do
SomeCompilerException a <- fromException x
cast a

---------------------------------------------------------------------
-- Make a subhierarchy for exceptions in the frontend of the compiler

data SomeFrontendException = forall e . Exception e => SomeFrontendException e

instance Show SomeFrontendException where
show (SomeFrontendException e) = show e

instance Exception SomeFrontendException where
toException = compilerExceptionToException
fromException = compilerExceptionFromException

frontendExceptionToException :: Exception e => e -> SomeException
frontendExceptionToException = toException . SomeFrontendException

frontendExceptionFromException :: Exception e => SomeException -> Maybe e
frontendExceptionFromException x = do
SomeFrontendException a <- fromException x
cast a

---------------------------------------------------------------------
-- Make an exception type for a particular frontend compiler exception

data MismatchedParentheses = MismatchedParentheses
deriving Show

instance Exception MismatchedParentheses where
toException = frontendExceptionToException
fromException = frontendExceptionFromException
```

Woof! That's a lot of code just to have nested exceptions.
Especially since Java devs can just write

```java
public class CompilerException extends Exception { ... }
public class FrontendException extends CompilerException {....}
```

This library attempts to help by providing a `newtype` wrapper you can use with `DerivingVia`.
With basic exceptions, you don't need this - the default methods on `Exception` default to a top-level exception.

```haskell
data EasyException = EasyException
deriving stock Show
deriving anyclass Exception
```

Let's make those nested exceptions.

```haskell
data SomeCompilerException = forall e . Exception e => SomeCompilerException e

deriving stock instance Show SomeCompilerException
deriving anyclass instance Exception SomeCompilerException

instance Hierarchy SomeCompilerException where
toParent = SomeCompilerException
fromParent (SomeCompilerException e) = cast e
```

The `Hierarchy` class is required to tell us how to unpack and pack things in the exception type.
Now let's get to the frontend exception.
It's a subtype of `SomeCompilerException`, so we'll derive the `Exception` instance using our `via`-type.

```haskell
data SomeFrontendException = forall e . Exception e => SomeFrontendException e

deriving stock instance Show SomeFrontendException
deriving
via (SomeFrontendException