effet-0.3.0.2: examples/Example/Error.hs
-- | Examples of the error effect.
module Example.Error where
-- base
import Control.Monad.IO.Class (MonadIO, liftIO)
import Prelude hiding (print)
-- hspec
import Test.Hspec (Spec, it, shouldBe)
-- effet
import Control.Effect.Error
import Control.Effect.Identity
import Control.Effect.Reader
import Hspec (print, shouldPrint)
--- Example Programs -----------------------------------------------------------
data DivideByZero = DivideByZero
deriving (Eq, Show)
-- | Divides two numbers, may yield an error when dividing by zero.
divide :: Error DivideByZero m => Int -> Int -> m Int
divide _ 0 = throwError DivideByZero
divide x y = pure $ x `div` y
-- | Divides two numbers and returns a default value in case of zero division.
catchDivide :: Error DivideByZero m => Int -> Int -> m Int
catchDivide x y =
catchError
( divide x y )
( \_ -> pure 1337 )
-- | Divides two numbers found in the readers, catches the division by zero
-- error and prints a String describing the result.
divideByReader :: ( Error DivideByZero m
, MonadIO m
, Reader' "numerator" Int m
, Reader' "divisor" Int m )
=> m ()
divideByReader = do
n <- ask' @"numerator"
d <- ask' @"divisor"
catchError
( do r <- divide n d
liftIO . print $ "Result: " ++ show r )
( \e ->
liftIO . print $ "Error: " ++ show e )
--- Test Cases -----------------------------------------------------------------
spec :: Spec
spec = do
it "divides normally" $
( runIdentity -- result: Either DivideByZero Int
. runError -- result: Monad m => m (Either DivideByZero Int)
$ divide 8 3 ) -- effects: Error DivideByZero
`shouldBe` Right 2
it "divides by zero" $
( runIdentity -- result: Either DivideByZero Int
. runError -- result: Monad m => m (Either DivideByZero Int)
$ divide 5 0 ) -- effects: Error DivideByZero
`shouldBe` Left DivideByZero
it "catches division by zero" $
( runIdentity -- result: Either DivideByZero Int
. runError -- result: Monad m => m (Either DivideByZero Int)
$ catchDivide 5 0 ) -- effects: Error DivideByZero
`shouldBe` Right 1337
it "catches normally" $
( runReader' @"divisor" 3 -- result: MonadIO m => m (Either DivideByZero ()),
-- unified with IO (Either DivideByZero ())
. runReader' @"numerator" 17 -- effects: Reader' "divisor", MonadIO
. runError -- effects: Reader' "numerator", Reader' "divisor", MonadIO
$ divideByReader ) -- effects: Error DivideByZero, Reader' "numerator",
-- Reader' "divisor", MonadIO
`shouldPrint` "\"Result: 5\"\n"
it "catches division by zero" $
( runReader' @"divisor" 0 -- result: MonadIO m => m (Either DivideByZero ()),
-- unified with IO (Either DivideByZero ())
. runReader' @"numerator" 17 -- effects: Reader' "divisor", MonadIO
. runError -- effects: Reader' "numerator", Reader' "divisor", MonadIO
$ divideByReader ) -- effects: Error DivideByZero, Reader' "numerator",
-- Reader' "divisor", MonadIO
`shouldPrint` "\"Error: DivideByZero\"\n"