🎓 A1Learner
🔍
0 of 47 lessons completed

Haskell MonadError Class

MonadError is a typeclass for computations that can report and handle failures. Any stack with an error channel can provide its operations.

ThrowError gives a Left result

ThrowError stops with the failure value missing. The result is a Left value.

import Control.Monad.Except

main :: IO ()
main = print (runExcept (throwError "missing" :: Except String Int))

CatchError recovers from failure

CatchError runs its handler after a failure. The handler returns 7, so the result is Right 7.

import Control.Monad.Except

main :: IO ()
main = print (runExcept (catchError (throwError "oops" :: Except String Int) (\_ -> return 7)))

Safe division reports zero

Safe division returns a result for 20 divided by 4 and a failure for division by zero. The two lines show both cases.

import Control.Monad.Except

safeDiv :: Int -> Int -> Except String Int
safeDiv x y = if y == 0 then throwError "zero" else return (x `div` y)

main :: IO ()
main = do
  print (runExcept (safeDiv 20 4))
  print (runExcept (safeDiv 20 0))

Example

import Control.Monad.Except

safeDiv :: Int -> Int -> Except String Int
safeDiv x y = if y == 0 then throwError "zero" else return (x `div` y)

main :: IO ()
main = do
  print (runExcept (do x <- safeDiv 100 4; y <- safeDiv x 5; return (x + y)))
  print (runExcept (do x <- safeDiv 100 0; y <- safeDiv x 5; return (x + y)))

Key points

  • ThrowError: throwError stops a computation with a failure value.
  • CatchError: catchError runs a handler when a computation fails.
  • Success: a successful computation passes through catchError unchanged.
  • Type: the failure value has one fixed type for a whole computation.
  • Reuse: the same error code works in Except and in a larger stack.

In this example, the first chain divides 100 by 4 and then by 5 and adds the results to give 30, while the second chain stops at division by zero.

Note

throwError is not an exception, it is a value in the result.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Haskell Playground

Exercise

What does catchError do when its computation succeeds?