エラーモナドを使ったエラー処理

ほとんど http://www.haskell.org/ghc/docs/latest/html/libraries/mtl/Control-Monad-Error.html#1 を写経しただけ。Error クラスのインスタンスにするのにどうすりゃいいかという話さえ分かってしまえば、あとは予想可能な例外として扱えばいいだけ。どうインスタンス化すりゃいいかがいまいち分かっていないのだけど。

import Control.Monad.Error (Error, noMsg, strMsg, throwError, catchError)

data LengthError
    = EmptyList -- ^ リストが空
    | OtherError String -- ^ その他のエラー

-- ListError を Error クラスのインスタンスにする. 例外として投げられるよ
-- うにするため.
instance Error LengthError where           
    noMsg = OtherError "A List Error!"
    strMsg s = OtherError s

instance Show LengthError where
    show EmptyList = "The list was empty!"
    show (OtherError msg) = msg

-- | LengthError を伴う関数の結果につかう型.
type LengthMonad = Either LengthError

-- | 引数が空のリストだったらエラーを返す head
safeHead :: [a] -> LengthMonad a
safeHead [] = throwError EmptyList
safeHead (x:_) = return x

-- | 引数が空のリストだったらエラーを返す tail
safeTail :: [a] -> LengthMonad [a]
safeTail [] = throwError EmptyList
safeTail (_:xs) = return xs

main = do put $ safeHead [1]
          put $ safeHead empty
          put $ safeTail [1, 2]
          put $ (safeTail empty `catchError` (\_ -> return []))
  where put (Left e) = print e
        put (Right x) = print x
        empty :: [Int]
        empty = []