A couple fun tricks I just found with Either/ExceptT:
If you want a function to return a result type that has multiple modes of failure/success, and you don’t want to separate them like
data Failure = FailA | FailB
data Success = SuccessA Int | SuccessB String
myFunc :: String -> Either Failure Success
myFunc s = do
when (null s) $ Left FailA
x <- thing s :: Either Failure Int
pure $ if x > 0 then SuccessA x else SuccessB s
You could use Either a a
to abort early with the final result, or end with the final result:
data Result = FailA | FailB | SuccessA Int | SuccessB String
myFunc :: String -> Result
myFunc s = either id id $ do
when (null s) $ Left FailA
x <- thing s :: Either Result Int
pure $ if x > 0 then SuccessA x else SuccessB s
And if you want to have early abort within just a single function to make it easier to read, just use Either a Void
:
myFunc :: String -> Int
myFunc s = either id absurd $ do
s' <-
case s of
"zero" -> returnE 0
'+' : s' -> pure s'
_ -> pure $ otherFunc s
returnE $ length s' * 2
where
returnE = Left