packages feed

AERN-Basics-2011.1: src/Numeric/AERN/Basics/Exception.hs

{-# LANGUAGE DeriveDataTypeable #-}
{-|
    Module      :  Numeric.AERN.Basics.Exception
    Description :  exception type to signal AERN specific errors  
    Copyright   :  (c) Michal Konecny
    License     :  BSD3

    Maintainer  :  mikkonecny@gmail.com
    Stability   :  experimental
    Portability :  portable
    
    An exception type to be thrown on various arithmetic exceptions
    whose proper pure handling would be inefficient.
    'Control.Exception.ArithmeticException' is not
    flexible enough, eg because often we will not be checking
    overflows but DomViolations instead.
    
    The default exeception policy is:
    
    * no operation should ever return DomViolation; when a DomViolation represents "any value"/bottom
      (eg with 0/0 or &infin - &infin),
      it should be rounded up to +∞ or down to -∞; when a DomViolation represent
      an illegal argument exception (eg with log(-1)), an AERN DomViolation exception should
      be thrown with an appropriate message
    
    * intervals support infinite endpoints
    
    * polynomial coefficients must be finite, overflows of coefficients detected
      and result in a special polynomial denoting the constant function +∞ or -∞
-}
module Numeric.AERN.Basics.Exception where

import Prelude hiding (catch)

import Control.Exception
import Data.Typeable
import System.IO.Unsafe

data AERNException =
    AERNException String
    | AERNIllegalValue String
    | AERNDomViolationException String
    | AERNMaybeDomViolationException String
    deriving (Show, Typeable)

instance Exception AERNException

evalCatchAERNExceptions :: String -> t -> Either AERNException t
evalCatchAERNExceptions contextDescription a =
    unsafePerformIO $ catch (evaluateEmbed a) handler
    where
    handler e@(AERNException msg) =
        do
        putStrLn $ "caught AERN exception: " ++ msg
        return (Left e)
    handler e@(AERNIllegalValue msg) =
        do 
        putStrLn $ "caught AERN illegal value exception: " ++ msg
        return (Left e)
    handler e@(AERNDomViolationException msg) =
        do 
        putStrLn $ "caught AERN operation domain violation exception: " ++ msg
        return (Left e)
    handler e@(AERNMaybeDomViolationException msg) =
        do 
        putStrLn $ "caught AERN potential operation domain violation exception: " ++ msg
        return (Left e)
    evaluateEmbed a =
        do
        aa <- evaluate a
        return $ Right aa

evalCatchDomViolationExceptions :: String -> t -> Either AERNException t
evalCatchDomViolationExceptions contextDescription a =
    case evalCatchAERNExceptions contextDescription a of
        Left e@(AERNDomViolationException _) -> Left e
        Left e@(AERNMaybeDomViolationException _) -> Left e
        Left e ->
            unsafePerformIO $
            do
            putStrLn $ contextDescription ++ ": rethrowing" 
            throw e
        r -> r

raisesAERNException :: String -> t -> Bool
raisesAERNException contextDescription a =
    case (evalCatchAERNExceptions contextDescription a) of
        (Left _) -> True
        _ -> False

raisesDomViolationException :: String -> t -> Bool
raisesDomViolationException contextDescription a =
    case (evalCatchDomViolationExceptions contextDescription a) of
        (Left _) -> True
        _ -> False

class HasLegalValues t where
  isLegal :: t -> Bool
  
detectIllegalValues :: (HasLegalValues t, Show t) => String -> t -> t
detectIllegalValues contextDescription value 
    | isLegal value = value
    | otherwise = 
        throw $ AERNIllegalValue $ 
            contextDescription ++ ": " ++ show value