Haskell Error Handling Guide — Either, Maybe, Exceptions, and Safe Patterns
In this tutorial, you will learn about Haskell Error Handling Guide. We cover key concepts, practical examples, and best practices to help you master this topic.
Haskell error handling prefers pure types (Maybe for absence, Either for error messages) over exceptions -- with ExceptT for transformer-based error propagation in monadic code, and catch/try/bracket for IO Exception Handling.
Maybe for Optional Values
-- Maybe: Nothing or Just value
safeDiv :: Int -> Int -> Maybe Int
safeDiv _ 0 = Nothing
safeDiv x y = Just (x `div` y)
-- Using with do notation
compute = do
a <- safeDiv 10 2 -- Just 5
b <- safeDiv a 0 -- Nothing (short-circuits)
return b
Either for Error Messages
-- Either: Left error or Right value
type Error = String
validateAge :: Int -> Either Error Int
validateAge n
| n < 0 = Left "Age cannot be negative"
| n > 150 = Left "Age seems too high"
| otherwise = Right n
-- Chaining errors
process :: String -> Either Error String
process input = do
age <- validateAge (read input)
return $ "Valid age: " ++ show age
with ExceptT
import Control.Monad.Except
type App = ExceptT String IO
runApp :: App a -> IO (Either String a)
runApp = runExceptT
app :: App ()
app = do
liftIO $ putStrLn "Enter age:"
input <- liftIO getLine
age <- case readMaybe input of
Nothing -> throwError "Invalid number"
Just n -> validateAge n
liftIO $ print age
IO Exceptions
import Control.Exception
-- Catch exceptions
safeReadFile :: FilePath -> IO (Either IOException String)
safeReadFile path = do
result <- try (readFile path)
return result
-- Using bracket for resource management
withFileSafe :: FilePath -> (Handle -> IO a) -> IO a
withFileSafe path = bracket (openFile path ReadMode) hClose
-- Custom exceptions
data AppError = NotFound String | PermissionDenied
deriving (Show)
instance Exception AppError
Common Mistakes
1. Using error/undefined in production
error "message" throws an exception that can't be caught in pure code. Use Either or Maybe instead.
2. Pattern matching on Left
Always handle both Left and Right. Forgetting Left cases causes runtime pattern match failures.
3. Not using bracket
File handles and other resources need bracket to ensure cleanup even on exceptions.
Practice Questions
1. What is the difference between Maybe and Either? Maybe signals absence (Nothing). Either carries an error value (Left) or success (Right).
2. How do you throw an error in ExceptT?
throwError "message" sets the Left value and short-circuits the computation.
3. How do you safely open a file?
Use bracket or withFile which guarantee the handle is closed even if an exception occurs.
FAQ
{{< faq question="Can I catch exceptions in pure code?" >}} No. Exception handling requires IO. For pure error handling, use Either or Maybe. {{< /faq >}}
{{< faq question="What is the difference between catch and try?" >}} catch runs a handler on exception. try returns Left on exception, Right on success (never throws). {{< /faq >}}
{{< faq question="What does bracket do?" >}} bracket acquire release body -- runs acquire, then body, then release (even if body throws). Like try-with-resources. {{< /faq >}}
What's Next
Now learn about testing in Haskell.
| Topic | Description | Link |
|---|---|---|
| Testing | Testing with HUnit/QuickCheck | {{< ref "19-tests" >}} |
| Parsing | Parser combinators | {{< ref "20-parsing" >}} |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro