Error handling is one of the most important—and overlooked—topics for
programmers, regardless of the language used. In Haskell, you will find
two major types of error handling employed: *pure error handling* and
*exceptions*.

When we speak of pure error handling, we are referring to algorithms that do not require anything from the IO monad. We can often implement error handling for them simply by using Haskell’s expressive data type system to our advantage. Haskell also has an exception system. Due to the complexities of lazy evaluation, exceptions in Haskell can be thrown anywhere, but caught only within the IO monad. In this chapter, we’ll consider both.

Let’s begin our discussion of error handling with a very simple function. Let’s say that we wish to perform division on a series of numbers. We have a constant numerator but wish to vary the denominator. We might come up with a function like this:

-- file: ch19/divby1.hs divBy :: Integral a => a -> [a] -> [a] divBy numerator = map (numerator `div`)

Very simple, right? We can play around
with this a bit in *ghci*:

`ghci>`

[50,25,10,6,5]`divBy 50 [1,2,5,8,10]`

`ghci>`

[100,50,33,25,20]`take 5 (divBy 100 [1..])`

This behaves as expected: `50 / 1`

is `50`

, `50 / 2`

is `25`

, and so forth.^{[40]} This even worked with the infinite list `[1..]`

. What happens if we sneak a `0`

into our list somewhere?

`ghci>`

[50,25,*** Exception: divide by zero`divBy 50 [1,2,0,8,10]`

Isn’t that interesting? *ghci* started displaying ...

Start Free Trial

No credit card required