-
Notifications
You must be signed in to change notification settings - Fork 0
/
Counter.hs
84 lines (64 loc) · 2.11 KB
/
Counter.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
{-# LANGUAGE Arrows #-}
{-# LANGUAGE QualifiedDo #-}
module Example.Counter where
import Control.Category (Category)
import qualified Control.Category as Cat
import Control.Arrow
import StateMachine
import Syntax
------------------------------------------------------------------------
data Command = Incr | Read
data Response = Ok | Sum Int
deriving Show
------------------------------------------------------------------------
newtype SM s i o = SM { stepSM :: i -> s -> (s, o) }
runSM :: SM s i o -> [i] -> s -> (s, [o])
runSM sm0 = go []
where
go acc [] s = (s, reverse acc)
go acc (i : is) s =
let
(s', o) = stepSM sm0 i s
in
go (o : acc) is s'
instance Category (SM s) where
id = SM (\i s -> (s, i))
SM g . SM f = SM (\i s -> let (s', j) = f i s in g j s')
instance Arrow (SM s) where
arr f = SM (\i s -> (s, f i))
first (SM f) = SM (\(i, k) s -> let (s', o) = f i s in (s', (o, k)))
instance ArrowChoice (SM s) where
SM f +++ SM g = SM (\e s -> either (\i -> Left <$> f i s) (\j -> Right <$> g j s) e)
counter :: SM Int Command Response
counter = proc i -> case i of
Incr -> do
s <- get -< ()
() <- put -< s + 1
returnA -< Ok
Read -> do
s <- get -< ()
returnA -< Sum s
where
get :: SM s () s
get = SM (\_i s -> (s, s))
put :: SM s s ()
put = SM (\s' _s -> (s', ()))
counter' :: (Arrow a, ArrowChoice a) => a (Command, Int) (Response, Int)
counter' = proc (i, s) -> case i of
Incr -> returnA -< (Ok, s + 1)
Read -> returnA -< (Sum s, s)
------------------------------------------------------------------------
counterSM :: FreeFunc Int (Either () ()) (Either () Int)
counterSM = sm $ kase incr get
where
incr = inl . pmodify (kadd 1)
get = inr . pget
counterSM2 :: FreeFunc (Int, Int) (Either () ()) (Either () Int)
counterSM2 = sm $ kase (inl . incr) (inr . get)
where
incr l = StateMachine.do
let (old, new) = split (pget l)
pput (pair old (padd 1 new))
get = psnd . pget
upgradeState :: FreeFunc () Int (Int, Int)
upgradeState = sm $ \oldState -> pair oldState (konst 0 unit)