1 {-# LANGUAGE DataKinds #-}
2 {-# LANGUAGE DeriveFunctor #-}
3 {-# LANGUAGE ConstraintKinds #-}
4 {-# LANGUAGE EmptyDataDecls #-}
5 {-# LANGUAGE FlexibleContexts #-}
6 {-# LANGUAGE FlexibleInstances #-}
7 {-# LANGUAGE KindSignatures #-}
8 {-# LANGUAGE MagicHash #-}
9 {-# LANGUAGE MultiParamTypeClasses #-}
10 {-# LANGUAGE ScopedTypeVariables #-}
11 {-# LANGUAGE TypeFamilies #-}
12 {-# LANGUAGE TypeOperators #-}
13 module Control.Monad.Classes.StateFix where
14 -- | 'MonadState' whose state is parameterized by the 'Monad' stack.
16 import Control.Applicative (Applicative(..))
18 import Control.Monad.Classes
19 import Control.Monad.Classes.EffectsFix
20 import Control.Monad.Trans.Class
21 import qualified Control.Monad.Trans.State.Lazy as SL
22 -- import qualified Control.Monad.Trans.State.Strict as SS -- TODO: when needed :)
23 import Data.Bool (Bool(..))
24 import Data.Function ((.))
25 import Data.Functor.Identity (Identity)
26 import GHC.Prim (Proxy#, proxy#)
29 -- * Type 'StateLazyFixT'
32 (st::{-StateLazyFixT st m-}(* -> *) -> *)
36 { unStateLazyFixT :: SL.StateT (st (StateLazyFixT st m)) m a }
38 instance Monad m => Applicative (StateLazyFixT st m) where
41 instance Monad m => Monad (StateLazyFixT st m) where
42 return = StateLazyFixT . return
43 m >>= f = StateLazyFixT (unStateLazyFixT m >>= unStateLazyFixT . f)
44 instance MonadTrans (StateLazyFixT st) where
45 lift = StateLazyFixT . lift
47 -- ** Type 'StateLazyFix'
49 = StateLazyFixT st Identity
51 -- * Type family 'StateFixCanDo'
53 type instance CanDo (StateLazyFixT s m) eff
56 type family StateFixCanDo s eff where
57 StateFixCanDo s (EffStateFix s) = 'True
58 StateFixCanDo s (EffReaderFix s) = 'True
59 StateFixCanDo s (EffLocalFix s) = 'True
60 StateFixCanDo s (EffWriterFix s) = 'True
61 StateFixCanDo s eff = 'False
63 -- * Class 'MonadStateFixN'
65 class Monad m => MonadStateFixN (n :: Peano) s m where
66 stateFixN :: Proxy# n -> (s m -> (a, s m)) -> m a
68 -- | Warning: only work when 'StateLazyFixT'
69 -- is the outermost 'Monad' (i.e. when @n@ @~@ 'Zero'),
70 -- because the state is paramaterized by this 'Monad'.
71 instance Monad m => MonadStateFixN 'Zero s (StateLazyFixT s m) where
72 stateFixN _ = StateLazyFixT . SL.state
74 -- ** Type 'MonadStateFixN'
76 -- | The @'MonadStateFix' s m@ constraint asserts that @m@ is a 'Monad' stack
77 -- that supports state operations on type @s@
78 type MonadStateFix (s::(* -> *) -> *) m
79 = MonadStateFixN (Find (EffStateFix s) m) s m
81 -- | Construct a state 'Monad' computation from a function
83 :: forall s m a. (MonadStateFix s m)
84 => (s m -> (a, s m)) -> m a
85 stateFix = stateFixN (proxy# :: Proxy# (Find (EffStateFix s) m))
87 -- | @'put' s@ sets the state within the 'Monad' to @s@
88 putFix :: MonadStateFix s m => s m -> m ()
89 putFix s = stateFix (\_ -> ((), s))
91 -- | Fetch the current value of the state within the 'Monad'
92 getFix :: MonadStateFix s m => m (s m)
93 getFix = stateFix (\s -> (s, s))
95 -- | Gets specific component of the state,
96 -- using a projection function supplied.
97 getsFix :: MonadStateFix s m => (s m -> a) -> m a
102 -- | Maps an old state to a new state inside a state 'Monad' layer
103 modifyFix :: MonadStateFix s m => (s m -> s m) -> m ()
104 modifyFix f = stateFix (\s -> ((), f s))
106 -- | A variant of 'modify' in which the computation
107 -- is strict in the new state.
108 modifyFix' :: MonadStateFix s m => (s m -> s m) -> m ()
109 modifyFix' f = stateFix (\s -> let s' = f s in s' `seq` ((), s'))
111 -- Return the 'Monad' parameter and the state.
113 :: st (StateLazyFixT st m)
114 -> StateLazyFixT st m a
115 -> m (a, st (StateLazyFixT st m))
116 runStateLazyFix s m = SL.runStateT (unStateLazyFixT m) s
118 -- Return the 'Monad' parameter.
121 => st (StateLazyFixT st m)
122 -> StateLazyFixT st m a
124 evalStateLazyFix s m = SL.evalStateT (unStateLazyFixT m) s
129 => st (StateLazyFixT st m)
130 -> StateLazyFixT st m a
131 -> m (st (StateLazyFixT st m))
132 execStateLazyFix s m = SL.execStateT (unStateLazyFixT m) s