packages feed

uniform-error-0.1.3: Uniform/Error.hs

----------------------------------------------------------------------
--
-- Module      :  Uniform.Error
--
----------------------------------------------------------------------

    {-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}
-- runErrorT is depreceiated but used in monads-tf
{-# OPTIONS_GHC -w #-}

module Uniform.Error
  ( module Uniform.Error
    -- module Uniform.Strings,
    , module Safe
    , module Control.Monad
    , module Control.Monad.Trans.Except
    , liftIO, MonadIO 
    , SomeException
    -- , module Control.Monad.IO.Class  
    
    -- module Control.Monad.Error, -- is monads-tf
    -- module Control.Excepcation, -- to avoid control.error
  )
where

import Control.Exception (Exception, SomeException, bracket, catch, throw, SomeException)
import Control.Monad  -- just to make it available everywhere
import Control.Monad.IO.Class (liftIO, MonadIO)
-- import "monads-tf" Control.Monad.Error (Error, ErrorT, ErrorType, MonadError, MonadIO, catchError, liftIO, runErrorT, throwError, unless, when)

-- ErrorT Text IO xxx becomes ErrIO xxx

import Control.Monad.Trans.Except
import Safe (headNote, readNote)
import Uniform.Strings hiding (S, (<.>), (</>))

instance CharChains2 IOError Text where
  show' = s2t . show

type ErrOrVal = Either Text

type ErrIO = ExceptT Text IO

-- instance Exception [Text]


toErrOrVal :: Either String a -> ErrOrVal a
toErrOrVal (Left s) = Left (s2t s)
toErrOrVal (Right r) = Right r

-- | runErr to avoid the depreceated message for runErrorT, which is identical
runErr :: ErrIO a -> IO (ErrOrVal a)
runErr = runExceptT

runErrorVoid :: ErrIO () -> IO ()
-- ^ run an operation in ErrIO which is not returning anything
-- simpler to use than runErr
runErrorVoid a = do
  res <- runErr a
  case res of
    Left msg -> error (t2s msg)
    Right _ -> return ()

undef :: Text -> a
undef = error . t2s
-- ^ for type specification, not to be evaluated

fromRightEOV :: ErrOrVal a -> a
fromRightEOV (Right a) = a
fromRightEOV (Left msg) = errorT ["fromrightEOV", msg]

bracketErrIO ::
  -- | computation to run first (\"acquire resource\")
  ErrIO a ->
  -- | computation to run last (\"release resource\")
  (a -> ErrIO b) ->
  -- | computation to run in-between
  (a -> ErrIO c) ->
  ErrIO c -- returns the value from the in-between computation
  --bracketErrIO before after thing = bracket before after thing
  -- no way to catch IO errors reliably in ErrIO -- missing Monad Mask or similar
bracketErrIO before after thing =
  fmap fromRightEOV . callIO $
    bracket
      ( do
          ra <- runErr $ before
          return ra --  (ra :: ErrOrVal a) )
      )
      (\a -> runErr $ after . fromRightEOV $ a)
      (\a -> runErr $ thing . fromRightEOV $ a)

-- instance Error Text

callIO ::  
    -- (MonadError m, MonadIO m, ErrorType m ~ Text) => 
    -- (MonadIO m) => 
            IO a -> ErrIO a
-- | this is using catch to grab all errors
callIO op = do
    r2 <- liftIO $
            do
                r <- op
                return $ Right r
            `catch` ( \e -> do
                        -- putStrLn "callIO catch caught error\n"
                        return . Left $  (e :: SomeException)
                    )
    case r2 of
        Left e -> do
      --                        putIOwords ["\ncallIO Left branch\n", showT e, "throwError\n"]
                        throwE (showT e)
        Right v -> return v


throwErrorWords :: [Text] -> ErrIO a
-- throw an error with a list of texts as a text
throwErrorWords = throwE . unwordsT


throwErrorT :: Text -> ErrIO a
-- throw an error - for compatibility with old code
throwErrorT = throwE  

catchError :: Monad m	=> ExceptT e m a	
                        -> (e -> ExceptT e' m a) -> ExceptT e' m a
-- catch Error in the ExceptT monad (but not others??)
catchError = catchE 

maybe2error :: Maybe a -> ErrIO a
maybe2error Nothing = fail "was Nothing"
maybe2error (Just a) = return a

errorT :: [Text] -> a
-- ^ a list of texts is output with failure
errorT = error . t2s . unwordsT

errorWords :: [Text] -> a
errorWords = errorT

fromJustNoteT :: [Text] -> Maybe a -> a
-- produce error with msg when Nothing, msg is list of texts
fromJustNoteT msgs a = fromJustNote (t2s . unlinesT $ msgs) a

fromRightNoteString :: Text -> Either String b -> b
-- produce an error when assuming that a value is Right
fromRightNoteString msg (Left a) = errorT ["fromRight", showT a, msg]
fromRightNoteString _ (Right a) = a

fromRightNote :: Text -> Either Text b -> b
-- produce an error when assuming that a value is Right
fromRightNote msg (Left a) = errorT ["fromRight", showT a, msg]
fromRightNote _ (Right a) = a

headNoteT :: [Text] -> [a] -> a
-- get head with a list of texts
headNoteT msg s = headNote (t2s $ unwords' msg) s

startProg :: Show a => Text -> ErrIO a -> IO ()
startProg programName mainProg =
      (do
        putIOwords
            [ "------------------ ",
                programName,
                " ----------------------------\n"
            ]
        r <-  runErr $ mainProg
        putIOwords
            [ "\n------------------",
                "main",
                programName,
                "\nreturning",
                either id showT r,
                "\n"
            ]
        return ()
        )
    `catch` ( \e -> do  -- here catch because in the IO monad 
                        -- (not ExceptT )
                     putIOwords
                       [ "startProg error caught\n",
                         programName, "\n",
                         showT (e :: SomeException)
                       ]
                     return ()
                 )