0 | ||| Provides mutable references as described in Lazy Functional State Threads.
 1 | module Control.Monad.ST
 2 |
 3 | import Data.IORef
 4 |
 5 | %default total
 6 |
 7 | ||| A mutable reference, bound to a state thread.
 8 | |||
 9 | ||| A value of type `STRef s a` contains a mutable `a`, bound to a "thread"
10 | ||| `s`. Any access to the reference must occur in an `ST s` monad with the
11 | ||| same "thread".
12 | export
13 | data STRef : Type -> Type -> Type where
14 |      MkSTRef : IORef a -> STRef s a
15 |
16 | ||| The `ST` monad allows for mutable access to references, but unlike `IO`, it
17 | ||| is "escapable".
18 | |||
19 | ||| The parameter `s` is a "thread" -- it ensures that access to mutable
20 | ||| references created in each thread must occur in that same thread.
21 | export
22 | data ST : Type -> Type -> Type where
23 |      MkST : IO a -> ST s a
24 |
25 | ||| Run a `ST` computation.
26 | export
27 | runST : (forall s . ST s a) -> a
28 | runST p
29 |     = let MkST prog = p {s = ()} in -- anything will do :)
30 |           unsafePerformIO prog
31 |
32 | export
33 | Functor (ST s) where
34 |   map fn (MkST st) = MkST $ fn <$> st
35 |
36 | export
37 | Applicative (ST s) where
38 |   pure = MkST . pure
39 |   MkST f <*> MkST a = MkST $ f <*> a
40 |
41 | export
42 | Monad (ST s) where
43 |   MkST p >>= k
44 |       = MkST $ do p' <- p
45 |                   let MkST kp = k p'
46 |                   kp
47 |
48 | ||| Create a new mutable reference with the given value.
49 | export
50 | newSTRef : a -> ST s (STRef s a)
51 | newSTRef val
52 |     = MkST $ do r <- newIORef val
53 |                 pure (MkSTRef r)
54 |
55 | ||| Read the value of a mutable reference.
56 | |||
57 | ||| This occurs within `ST s` to prevent `STRef`s from being usable if they are
58 | ||| "leaked" via `runST`.
59 | %inline
60 | export
61 | readSTRef : STRef s a -> ST s a
62 | readSTRef (MkSTRef r) = MkST $ readIORef r
63 |
64 | ||| Write to a mutable reference.
65 | %inline
66 | export
67 | writeSTRef : STRef s a -> (val : a) -> ST s ()
68 | writeSTRef (MkSTRef r) val = MkST $ writeIORef r val
69 |
70 | ||| Apply a function to the contents of a mutable reference.
71 | export
72 | modifySTRef : STRef s a -> (a -> a) -> ST s ()
73 | modifySTRef ref f
74 |     = do val <- readSTRef ref
75 |          writeSTRef ref (f val)
76 |