Reputation: 10541
Describe a problem in several words. Guess I have an algorithms to check something, and depending on algorithm it can fail with slightly different errors, for example:
data Error1 = Error1
data Error2 = Error2
data Error3 = Error3
class Algorithm a where
type CanFailWith a :: *
check :: Something -> Maybe (CanFailWith a)
instance Algorithm FirstAlgorithm where
type CanFailWith FirstAlgorithm = Either Error1 Error2
...
instance Algorithm SecondAlgorithm where
type CanFailWith SecondAlgorithm = Either Error1 (Either Error2 Error3)
...
This option is not very friendly to user because of difficulty to work with it's branchy structure, e.g.
testError (Left Error1) = ...
testError (Right (Left Error2)) = ...
testError (Right (Right Error3)) = ...
It looks not so bad with three errors, but it worth with every extra error.
Error could be a simple sum type:
data Error = Error1
| Error2
| Error3
But in this case I force user to cover impossible case in first algorithm, that can not fail with Error3
A question is: is there any common and desirable simple to end user solutions for extending errors?
Upvotes: 1
Views: 123
Reputation: 33637
You can try something like this where each algo has its own error sum type.
{-# LANGUAGE TypeFamilies #-}
class Algorithm a where
data CanFailWith a :: *
check :: a -> [Int] -> Maybe (CanFailWith a)
data FirstAlgo = FirstAlgo deriving (Show)
instance Algorithm FirstAlgo where
data CanFailWith FirstAlgo = FError1 | FError2
check a x = Nothing
data SecondAlgo = SecondAlgo deriving (Show)
instance Algorithm SecondAlgo where
data CanFailWith SecondAlgo = SError1 | SError2 | SError3
check a x = Nothing
testError :: CanFailWith SecondAlgo -> ()
testError SError1 = ()
testError SError2 = ()
testError SError3 = ()
Upvotes: 2