[Haskell-beginners] exception, not in IO

Kees Bleijenberg k.bleijenberg at lijbrandt.nl
Mon Jul 15 16:01:04 CEST 2013


I don't understand all of it. This is what I've done

{-# LANGUAGE OverloadedStrings,DeriveDataTypeable #-}
module Test()

import Text.JSON
import Text.JSON.Generic
import Control.Exception
import Control.Monad

data Glass = Glass { a:: String,
                     b:: String} deriving (Show,Typeable,Eq,Data,Read)

data MyError = UnknownError deriving Show

glassDecode :: String -> (Either MyError Glass)
glassDecode s = Right ((decodeJSON s) :: Glass)
glassEncode :: Glass -> Either MyError String
glassEncode g = return $ encodeJSON g

convert :: String -> Either MyError String
convert = glassEncode <=< glassDecode

test  = convert "{\"a\":\"blah\",\"b\":\"blahb\"}"
test2  = convert "{\"\":\"blah\",\"b\":\"blahb\"}"

If I call test I get back Right <theInputString>
If I call test2 (invalid string) I get Right "{*** Exception: fromJSON:
field does not exist a"
The good news is that the program doesn't halt any more. 

How do I transform the last Right to a Left (without changing the source in
Text.JSON.Generic) if there is a error?  The code in Text.JSON.Generic calls
error "xxx" if something is wrong.


IO is just one of the many monads with exception support.  For your case,
since JSON parsing is a pure process, you would want to use a pure exception
monad like `Maybe` or `Either MyError`:

    data MyError
        = InvalidDateField
        | {- ... -}
        | UnknownError

There is nothing wrong with using regular exception types, if you wish, in
which case you might use `Either SomeException`.  Then separate

    decode :: String -> Either MyError Glass
    encode :: Glass -> String

Finally the conversion function is as simple as:

    convert :: String -> Either MyError String
    convert = fmap encode . decode

If `encode` can fail as well and exceptions are regular Haskell

    import Control.Exception
    import Control.Monad

    decode :: String -> Either SomeException Glass
    encode :: Glass -> Either SomeException String

    convert :: String -> Either SomeException String
    convert = encode <=< decode

More information about the Beginners mailing list