-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathError.hs
85 lines (74 loc) · 3.39 KB
/
Error.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
-- | 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"