-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathState.hs
66 lines (57 loc) · 2.28 KB
/
State.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
-- | Examples of the state effect.
module Example.State where
-- hspec
import Test.Hspec (Spec, it, shouldBe)
-- effet
import Control.Effect.Identity
import Control.Effect.State
import qualified Control.Effect.State.Lazy as L
import qualified Control.Effect.State.Strict as S
--- Example Programs -----------------------------------------------------------
-- | Increments the state.
increment :: (Num n, State n m) => m ()
increment = modify (+1)
-- | Increments the state tagged "s" by 3 and adds up the old and new values.
incrementWithResult :: State' "s" Int m => m String
incrementWithResult = do
before <- get' @"s"
modify' @"s" (+3)
after <- get' @"s"
pure . show $ before + after
-- | Increments two elements in a tuple.
incrementBoth :: (Num n1, Num n2, State (n1,n2) m) => m ()
incrementBoth = modify (\(x,y) -> (x+1, y+1))
-- | Increments the state tagged "foo" by 1,
-- increments the state tagged "bar" by 2,
-- then adds up the two states.
twoStates :: (State' "foo" Int m, State' "bar" Int m) => m Int
twoStates = do
tagState' @"foo" $ increment
tagState' @"bar" $ increment >> increment
foo <- get' @"foo"
bar <- get' @"bar"
pure $ foo + bar
--- Test Cases -----------------------------------------------------------------
spec :: Spec
spec = do
it "evaluates increment" $
( runIdentity -- result: Int
. L.execState 5 -- result: (Num n, Monad m) => m n
$ increment -- effects: Num n => State n
) `shouldBe` (6::Int)
it "evaluates incrementWithResult" $
( runIdentity -- result: (Int, String)
. S.runState' @"s" 5 -- result: Monad m => m (Int, String)
$ incrementWithResult -- effects: State' "s" Int
) `shouldBe` (8, "13")
it "evaluates incrementBoth" $
( runIdentity -- result: (Int, Int)
. L.execState (1,2) -- result: (Num n1, Num n2, Monad m) => m (n1, n2)
$ incrementBoth -- effects: (Num n1, Num n2) => State (n1, n2)
) `shouldBe` (2::Int, 3::Int)
it "evaluates twoStates" $
( runIdentity -- result: (Int, (Int, Int))
. L.runState' @"foo" 3 -- result: Monad m => m (Int, (Int, Int))
. S.runState' @"bar" 5 -- effects: State' "foo" Int
$ twoStates -- effects: State' "foo" Int, State' "bar" Int
) `shouldBe` (4, (7, 11))