Skip to content
Slava Akhmechet edited this page Oct 13, 2006 · 1 revision

Perhaps the most compelling feature of monads is composition - ability to mix and match monads that serve different purposes to write well designed, extensible code. We can demonstrate Haskell's ability to rapidly adapt to change by refactoring our program one more time - this time to implement error handling. At this point our interpreter will crash if we type in code that cannot be parsed or uses an undefined symbol. We can easily fix it with the standard Error monad - a monad that implements exceptions (try implementing something like that as a Java library!)

The first thing we need to do is define a type that will be responsible for handling errors. We'll use the Error monad to do most of the work and we'll compose it with the IO monad so we can still perform input output:

type BlaiseError = ErrorT String IO

We should now redefine BlaiseResult to account for a possibility of an error:

type BlaiseResult = StateT Context BlaiseError Expr

That's it! We can now rewrite our code to throw and catch exceptions - a feature implemented in Haskell as a library!

eval (BlaiseSymbol s) =
    do sym_table <- get
       if s `Map.member` sym_table == True
       then return (sym_table Map.! s)
       else throwError ("Symbol " ++ s ++ " is unbound.")

parse source =
        case (Text.ParserCombinators.Parsec.parse
              parseExpr "" source) of
      Right x -> return x
      Left e -> throwError $ show e

do expr <- parse x
   evaledExpr <- eval expr
   liftIO $ putStrLn ((show evaledExpr))
   repl
`catchError` (\e -> do liftIO $ putStrLn e
                       repl)

We can now make syntax errors and try to look up symbols that don't exist and get a meaningful error message. I deliberately avoided handling errors that deal with calling functions with a wrong number of arguments or mismatched types. I encourage you to dive into the interpreter's code and implement this yourself - it will be a rewarding experience!

Clone this wiki locally