{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-} -------------------------------------------------------------------------------- -- | -- Module : Data.StateVar -- Copyright : (c) Sven Panne 2009 -- (c) HATTORI,HIROKI 2014 -- License : BSD-style (see the file LICENSE) -- -- Maintainer : HATTORI, HIROKI -- Stability : stable -- Portability : portable -- -- Data.StateVarがIO専用なのが気にくわないので変換できるようにしただけ -- -------------------------------------------------------------------------------- module Data.StateVar.Trans ( -- * Readable State Variables HasGetter(..), GettableStateVar, makeGettableStateVar, -- * Writable State Variables HasSetter(..), SettableStateVar, makeSettableStateVar, -- * General State Variables StateVar, makeStateVar, makePtrVar, -- * Utility Functions ($~), ($=!), ($~!), (&), (^=), (^~), (^=!), (^~!), (^.), (@=) ) where import Data.IORef (IORef, readIORef, writeIORef) import GHC.Conc (STM, TVar, readTVar, writeTVar) import Data.STRef (STRef, readSTRef, writeSTRef) import Foreign.Ptr (Ptr) import Foreign.Storable import Control.Monad.ST.Safe (ST) import Control.Monad.Trans (MonadTrans(..)) import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.Reader.Class (MonadReader(..)) -------------------------------------------------------------------------------- infixr 2 $= -------------------------------------------------------------------------------- -- | The class of all readable state variables. class HasGetter g m | g -> m where -- | Read the value of a state variable. get :: g a -> m a instance HasGetter IORef IO where get = readIORef {-# INLINE get #-} instance HasGetter TVar STM where get = readTVar {-# INLINE get #-} instance HasGetter (STRef s) (ST s) where get = readSTRef {-# INLINE get #-} -- | A concrete implementation of a read-only state variable, carrying an IO -- action to read the value. newtype GettableStateVar m a = GettableStateVar (m a) instance HasGetter (GettableStateVar m) m where get (GettableStateVar g) = g {-# INLINE get #-} -- | Construct a 'GettableStateVar' from an IO action. makeGettableStateVar :: m a -> GettableStateVar m a makeGettableStateVar = GettableStateVar {-# INLINE makeGettableStateVar #-} -------------------------------------------------------------------------------- -- | The class of all writable state variables. class HasSetter s m where -- | Write a new value into a state variable. ($=) :: s a -> a -> m () instance HasSetter IORef IO where ($=) = writeIORef {-# INLINE ($=) #-} instance HasSetter TVar STM where ($=) = writeTVar {-# INLINE ($=) #-} instance HasSetter (STRef s) (ST s) where ($=) = writeSTRef {-# INLINE ($=) #-} -- | A concrete implementation of a write-only state variable, carrying an IO -- action to write the new value. newtype SettableStateVar m a = SettableStateVar (a -> m ()) instance HasSetter (SettableStateVar m) m where ($=) (SettableStateVar s) a = s a {-# INLINE ($=) #-} -- | Construct a 'SettableStateVar' from an IO action. makeSettableStateVar :: (a -> m ()) -> SettableStateVar m a makeSettableStateVar = SettableStateVar {-# INLINE makeSettableStateVar #-} -------------------------------------------------------------------------------- -- | A concrete implementation of a readable and writable state variable, -- carrying one IO action to read the value and another IO action to write the -- new value. data StateVar m a = StateVar (GettableStateVar m a) (SettableStateVar m a) instance HasGetter (StateVar m) m where get (StateVar g _) = get g {-# INLINE get #-} instance HasSetter (StateVar m) m where ($=) (StateVar _ s) a = s $= a {-# INLINE ($=) #-} -- | Construct a 'StateVar' from two IO actions, one for reading and one for -- writing. makeStateVar :: m a -> (a -> m ()) -> StateVar m a makeStateVar g s = StateVar (makeGettableStateVar g) (makeSettableStateVar s) {-# INLINE makeStateVar #-} makePtrVar :: (MonadIO m, Storable a) => Ptr a -> StateVar m a makePtrVar p = makeStateVar (liftIO $ peek p) (liftIO . poke p) {-# INLINE makePtrVar #-} -------------------------------------------------------------------------------- -- | A modificator convenience function, transforming the contents of a state -- variable with a given funtion. ($~) :: (Monad m, HasGetter v m, HasSetter v m) => v a -> (a -> a) -> m () v $~ f = get v >>= ($=) v . f {-# INLINE ($~) #-} -- | A variant of '$=' which is strict in the value to be set. ($=!) :: (Monad m, HasSetter s m) => s a -> a -> m () v $=! x = x `seq` v $= x {-# INLINE ($=!) #-} -- | A variant of '$~' which is strict in the transformed value. ($~!) :: (Monad m, HasGetter v m, HasSetter v m) => v a -> (a -> a) -> m () v $~! f = get v >>= ($=!) v . f {-# INLINE ($~!) #-} -------------------------------------------------------------------------------- (&) :: s -> (s -> t) -> t s & t = t s {-# INLINE (&) #-} infixl 8 ^=, ^~, ^=!, ^~!, ^. (^=) :: HasSetter g m => (s -> g a) -> a -> s -> m () (fv ^= v) s = fv s $= v {-# INLINE (^=) #-} (^~) :: (Monad m, HasGetter g m, HasSetter g m) => (s -> g a) -> (a -> a) -> s -> m () (fv ^~ f) s = v $~ f where v = fv s {-# INLINE (^~) #-} (^=!) :: (Monad m, HasSetter g m) => (s -> g a) -> a -> s -> m () (fv ^=! x) s = v $=! x where v = fv s {-# INLINE (^=!) #-} (^~!) :: (Monad m, HasGetter g m, HasSetter g m) => (s -> g a) -> (a ->a) -> s -> m () (fv ^~! f) s = v $~! f where v = fv s {-# INLINE (^~!) #-} (^.) :: (Monad m, HasGetter g m, HasGetter h m) => (s -> g a) -> (a -> h b) -> s -> GettableStateVar m b (fg ^. fh) s = makeGettableStateVar $ get (fg s) >>= get . fh {-# INLINE (^.) #-} -------------------------------------------------------------------------------- (@=) :: (Monad m, MonadTrans n, MonadReader s (n m), HasSetter g m) => (s -> g a) -> a -> n m () fv @= v = ask >>= lift . (fv ^= v) {-# INLINE (@=) #-}