packages feed

atp-0.1.0.0: src/ATP/Error.hs

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DeriveTraversable #-}

{-|
Module       : ATP.Error
Description  : Monads and monad transformers for computations with errors.
Copyright    : (c) Evgenii Kotelnikov, 2019-2021
License      : GPL-3
Maintainer   : evgeny.kotelnikov@gmail.com
Stability    : experimental

Monads and monad transformers for computations with errors.
-}

module ATP.Error (
  Error(..),
  Partial,
  PartialT(..),
  liftPartial,
  isSuccess,
  isFailure,
  exitCodeError,
  timeLimitError,
  memoryLimitError,
  parsingError,
  proofError,
  otherError
) where

import Control.Monad.Except (MonadTrans, ExceptT(..), MonadError(..), runExcept)
import Data.Either (isLeft, isRight)
import Data.Functor.Identity (Identity)
import Data.Text (Text)
import qualified Data.Text as T (pack)


-- | The error that might occur while reconstructing the proof.
data Error
  = ExitCodeError Int Text
  -- ^ The theorem prover terminated with a non-zero exit code.
  | TimeLimitError
  -- ^ The theorem prover reached the time limit without producing a solution.
  | MemoryLimitError
  -- ^ The theorem prover reached the memory limit without producing a solution.
  | ParsingError Text
  -- ^ The output of the theorem prover is not a well-formed TSTP.
  | ProofError Text
  -- ^ The proof returned by the theorem prover is not well-formed.
  | OtherError Text
  -- ^ An uncategorized error.
  deriving (Show, Eq, Ord)

-- | The type of computations that might fail with an @'Error'@.
type Partial = PartialT Identity

-- | A monad transformer that adds failing with an @'Error'@ to other monads.
newtype PartialT m a = PartialT {
  runPartialT :: ExceptT Error m a
} deriving (Show, Eq, Ord, Functor, Applicative, Monad, MonadTrans, MonadError Error)

-- | Extractor for computations in the @'Partial'@ monad.
liftPartial :: Partial a -> Either Error a
liftPartial = runExcept . runPartialT

-- | Check whether a partial computation resulted successfully.
isSuccess :: Partial a -> Bool
isSuccess = isRight . liftPartial

-- | Check whether a partial computation resulted with an error.
isFailure :: Partial a -> Bool
isFailure = isLeft . liftPartial

-- | A smart constructor for a computation failed with an @'ExitCodeError'@.
exitCodeError :: Monad m => Int -> Text -> PartialT m a
exitCodeError exitCode err = PartialT (throwError $ ExitCodeError exitCode err)

-- | A smart constructor for a computation failed with a @'TimeLimitError'@.
timeLimitError :: Monad m => PartialT m a
timeLimitError = PartialT (throwError TimeLimitError)

-- | A smart constructor for a computation failed with a @'MemoryLimitError'@.
memoryLimitError :: Monad m => PartialT m a
memoryLimitError = PartialT (throwError MemoryLimitError)

-- | A smart constructor for a computation failed with a @'ParsingError'@.
parsingError :: Monad m => String -> PartialT m a
parsingError = PartialT . throwError . ParsingError . T.pack

-- | A smart constructor for a computation failed with a @'ProofError'@.
proofError :: Monad m => String -> PartialT m a
proofError = PartialT . throwError . ProofError . T.pack

-- | A smart constructor for a computation failed with a @'OtherError'@.
otherError :: Monad m => String -> PartialT m a
otherError = PartialT . throwError . OtherError . T.pack