StateVar 1.0.1.1 → 1.1.0.0
raw patch · 5 files changed
+237/−92 lines, 5 filesdep +stmdep +transformersdep ~basePVP ok
version bump matches the API change (PVP)
Dependencies added: stm, transformers
Dependency ranges changed: base
API changes (from Hackage documentation)
- Data.StateVar: GettableStateVar :: (IO a) -> GettableStateVar a
- Data.StateVar: instance Applicative GettableStateVar
- Data.StateVar: instance Functor GettableStateVar
- Data.StateVar: instance HasGetter GettableStateVar
- Data.StateVar: instance HasGetter IORef
- Data.StateVar: instance HasGetter StateVar
- Data.StateVar: instance HasSetter IORef
- Data.StateVar: instance HasSetter SettableStateVar
- Data.StateVar: instance HasSetter StateVar
- Data.StateVar: instance Monad GettableStateVar
- Data.StateVar: newtype GettableStateVar a
+ Data.StateVar: class HasSetter t a => HasUpdate t a b | t -> a b where ($~) = defaultUpdate ($~!) = defaultUpdateStrict
+ Data.StateVar: instance HasGetter (IO a) a
+ Data.StateVar: instance HasGetter (IORef a) a
+ Data.StateVar: instance HasGetter (STM a) a
+ Data.StateVar: instance HasGetter (StateVar a) a
+ Data.StateVar: instance HasGetter (TVar a) a
+ Data.StateVar: instance HasSetter (IORef a) a
+ Data.StateVar: instance HasSetter (SettableStateVar a) a
+ Data.StateVar: instance HasSetter (StateVar a) a
+ Data.StateVar: instance HasSetter (TVar a) a
+ Data.StateVar: instance HasUpdate (IORef a) a a
+ Data.StateVar: instance HasUpdate (StateVar a) a a
+ Data.StateVar: instance HasUpdate (TVar a) a a
+ Data.StateVar: instance Storable a => HasGetter (Ptr a) a
+ Data.StateVar: instance Storable a => HasSetter (Ptr a) a
+ Data.StateVar: instance Storable a => HasUpdate (Ptr a) a a
+ Data.StateVar: instance Typeable SettableStateVar
+ Data.StateVar: instance Typeable StateVar
+ Data.StateVar: mapStateVar :: (b -> a) -> (a -> b) -> StateVar a -> StateVar b
+ Data.StateVar: type GettableStateVar = IO
- Data.StateVar: ($=!) :: HasSetter s => s a -> a -> IO ()
+ Data.StateVar: ($=!) :: (HasSetter t a, MonadIO m) => t -> a -> m ()
- Data.StateVar: ($=) :: HasSetter s => s a -> a -> IO ()
+ Data.StateVar: ($=) :: (HasSetter t a, MonadIO m) => t -> a -> m ()
- Data.StateVar: ($~!) :: (HasGetter v, HasSetter v) => v a -> (a -> a) -> IO ()
+ Data.StateVar: ($~!) :: (HasUpdate t a b, MonadIO m) => t -> (a -> b) -> m ()
- Data.StateVar: ($~) :: (HasGetter v, HasSetter v) => v a -> (a -> a) -> IO ()
+ Data.StateVar: ($~) :: (HasUpdate t a b, MonadIO m) => t -> (a -> b) -> m ()
- Data.StateVar: StateVar :: (GettableStateVar a) -> (SettableStateVar a) -> StateVar a
+ Data.StateVar: StateVar :: (IO a) -> (a -> IO ()) -> StateVar a
- Data.StateVar: class HasGetter g
+ Data.StateVar: class HasGetter t a | t -> a
- Data.StateVar: class HasSetter s
+ Data.StateVar: class HasSetter t a | t -> a
- Data.StateVar: get :: HasGetter g => g a -> IO a
+ Data.StateVar: get :: (HasGetter t a, MonadIO m) => t -> m a
Files
- CHANGELOG.md +5/−0
- LICENSE +2/−1
- README.md +1/−0
- StateVar.cabal +25/−5
- src/Data/StateVar.hs +204/−86
+ CHANGELOG.md view
@@ -0,0 +1,5 @@+1.1+---+* Melded the API of `foreign-var` 0.1 with the API of `StateVar` 1.0.1.1+* Introduced `HasUpdate`, which permits a wider array of uses of these combinators, including usecases that must update atomically.+* Switched to multi-parameter typeclasses. This permits `Ptr a` to be directly employed as an instance of `HasGetter`, `HasUpdate`, and `HasSetter`.
LICENSE view
@@ -1,4 +1,5 @@-Copyright (c) 2009, Sven Panne+Copyright (c) 2014-2015, Edward Kmett+Copyright (c) 2009-2014, Sven Panne All rights reserved. Redistribution and use in source and binary forms, with or without
+ README.md view
@@ -0,0 +1,1 @@+[](https://hackage.haskell.org/package/StateVar) [](https://travis-ci.org/haskell-opengl/StateVar)
StateVar.cabal view
@@ -1,25 +1,45 @@ name: StateVar-version: 1.0.1.1+version: 1.1.0.0 synopsis: State variables description: This package contains state variables, which are references in the IO monad, like IORefs or parts of the OpenGL state. homepage: https://github.com/haskell-opengl/StateVar bug-reports: https://github.com/haskell-opengl/StateVar/issues+copyright: Copyright (C) 2014-2015 Edward A. Kmett, 2009-2014 Sven Panne license: BSD3 license-file: LICENSE-author: Sven Panne+author: Sven Panne and Edward Kmett maintainer: Sven Panne <svenpanne@gmail.com> category: Data build-type: Simple cabal-version: >=1.10+extra-source-files: README.md CHANGELOG.md library- exposed-modules: Data.StateVar- build-depends: base >= 3 && < 5+ exposed-modules:+ Data.StateVar++ build-depends:+ base >= 4 && < 5,+ stm >= 2.0 && < 2.5,+ transformers >= 0.2 && < 0.5+ default-language: Haskell2010- hs-Source-Dirs: src+ other-extensions:+ CPP+ DeriveDataTypeable+ MultiParamTypeClasses+ FunctionalDependencies+ FlexibleInstances+ TypeFamilies++ hs-source-dirs: src ghc-options: -Wall++ if impl(ghc>=7.4)+ -- other-extensions: DefaultSignatures+ cpp-options: -DUSE_DEFAULT_SIGNATURES=1 source-repository head type: git
src/Data/StateVar.hs view
@@ -1,7 +1,16 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE FlexibleInstances #-}+#if USE_DEFAULT_SIGNATURES+{-# LANGUAGE DefaultSignatures #-}+#endif+{-# LANGUAGE TypeFamilies #-} -------------------------------------------------------------------------------- -- | -- Module : Data.StateVar--- Copyright : (c) Sven Panne 2014+-- Copyright : (c) Edward Kmett 2014-2015, Sven Panne 2009-2014 -- License : BSD3 -- -- Maintainer : Sven Panne <svenpanne@gmail.com>@@ -12,7 +21,7 @@ -- the OpenGL state. Note that state variables are not neccessarily writable or -- readable, they may come in read-only or write-only flavours, too. As a very -- simple example for a state variable, consider an explicitly allocated memory--- buffer. This buffer can easily be converted into a 'StateVar':+-- buffer. This buffer could easily be converted into a 'StateVar': -- -- @ -- makeStateVarFromPtr :: Storable a => Ptr a -> StateVar a@@ -32,6 +41,16 @@ -- print x -- @ --+-- However, 'Ptr' can be used directly through the same API:+--+-- @+-- do p <- malloc :: IO (Ptr Int)+-- p $= 11+-- p $~ (+ 22)+-- x <- get p+-- print x+-- @+-- -- 'IORef's are state variables, too, so an example with them looks extremely -- similiar: --@@ -44,117 +63,216 @@ -- @ -------------------------------------------------------------------------------- -module Data.StateVar (- -- * Readable State Variables- HasGetter(..),- GettableStateVar(..), makeGettableStateVar,- -- * Writable State Variables- HasSetter(..),- SettableStateVar(..), makeSettableStateVar,- -- * General State Variables- StateVar(..), makeStateVar,- -- * Utility Functions- ($~), ($=!), ($~!)-) where+module Data.StateVar+ (+ -- * Readable State Variables+ HasGetter(get)+ , GettableStateVar, makeGettableStateVar+ -- * Writable State Variables+ , HasSetter(($=)), ($=!)+ , SettableStateVar(SettableStateVar), makeSettableStateVar+ -- * Updatable State Variables+ , HasUpdate(($~), ($~!))+ , StateVar(StateVar), makeStateVar+ , mapStateVar+ ) where -import Control.Applicative ( Applicative(..) )-import Data.IORef ( IORef, readIORef, writeIORef )+import Control.Concurrent.STM+import Control.Monad.IO.Class+import Data.IORef+import Data.Typeable+import Foreign.Ptr+import Foreign.Storable ---------------------------------------------------------------------------------+--------------------------------------------------------------------+-- * StateVar+-------------------------------------------------------------------- -infixr 2 $=+-- | 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.+--+-- This data type represents a piece of mutable, imperative state+-- with possible side-effects. These tend to encapsulate all sorts+-- tricky behavior in external libraries, and may well throw+-- exceptions.+--+-- Inhabitants __should__ satsify the following properties.+--+-- In the absence of concurrent mutation from other threads or a+-- thrown exception:+--+-- @+-- do x <- 'get' v; v '$=' y; v '$=' x+-- @+--+-- should restore the previous state.+--+-- Ideally, in the absence of thrown exceptions:+--+-- @+-- v '$=' a >> 'get' v+-- @+--+-- should return @a@, regardless of @a@. In practice some 'StateVar's only+-- permit a very limited range of value assignments, and do not report failure.+data StateVar a = StateVar (IO a) (a -> IO ()) deriving Typeable ---------------------------------------------------------------------------------+-- | Construct a 'StateVar' from two IO actions, one for reading and one for+--- writing.+makeStateVar+ :: IO a -- ^ getter+ -> (a -> IO ()) -- ^ setter+ -> StateVar a+makeStateVar = StateVar --- | The class of all readable state variables.-class HasGetter g where- -- | Read the value of a state variable.- get :: g a -> IO a+-- | Change the type of a 'StateVar'+mapStateVar :: (b -> a) -> (a -> b) -> StateVar a -> StateVar b+mapStateVar ba ab (StateVar ga sa) = StateVar (fmap ab ga) (sa . ba)+{-# INLINE mapStateVar #-} -instance HasGetter IORef where- get = readIORef+-- | A concrete implementation of a write-only state variable, carrying an IO+-- action to write the new value.+newtype SettableStateVar a = SettableStateVar (a -> IO ())+ deriving Typeable --- | A concrete implementation of a read-only state variable, carrying an IO+-- | Construct a 'SettableStateVar' from an IO action for writing.+makeSettableStateVar+ :: (a -> IO ()) -- ^ setter+ -> SettableStateVar a+makeSettableStateVar = SettableStateVar+{-# INLINE makeSettableStateVar #-}++-- | A concrete implementation of a read-only state variable is simply an IO -- action to read the value.-newtype GettableStateVar a = GettableStateVar (IO a)+type GettableStateVar = IO -instance HasGetter GettableStateVar where- get (GettableStateVar g) = g+-- | Construct a 'GettableStateVar' from an IO action.+makeGettableStateVar+ :: IO a -- ^ getter+ -> GettableStateVar a+makeGettableStateVar = id+{-# INLINE makeGettableStateVar #-} -instance Functor GettableStateVar where- fmap f (GettableStateVar g) = GettableStateVar (fmap f g)+--------------------------------------------------------------------+-- * HasSetter+-------------------------------------------------------------------- -instance Applicative GettableStateVar where- pure = GettableStateVar . pure- GettableStateVar g <*> GettableStateVar h = GettableStateVar (g <*> h)+infixr 2 $=, $=! -instance Monad GettableStateVar where- return = pure- GettableStateVar g >>= h = GettableStateVar (g >>= get . h)+-- | This is the class of all writable state variables.+class HasSetter t a | t -> a where+ -- | Write a new value into a state variable.+ ($=) :: MonadIO m => t -> a -> m () --- | Construct a 'GettableStateVar' from an IO action.-makeGettableStateVar :: IO a -> GettableStateVar a-makeGettableStateVar = GettableStateVar+-- | This is a variant of '$=' which is strict in the value to be set.+($=!) :: (HasSetter t a, MonadIO m) => t -> a -> m ()+p $=! a = (p $=) $! a+{-# INLINE ($=!) #-} ---------------------------------------------------------------------------------+instance HasSetter (SettableStateVar a) a where+ SettableStateVar f $= a = liftIO (f a)+ {-# INLINE ($=) #-} --- | The class of all writable state variables.-class HasSetter s where- -- | Write a new value into a state variable.- ($=) :: s a -> a -> IO ()+instance HasSetter (StateVar a) a where+ StateVar _ s $= a = liftIO $ s a+ {-# INLINE ($=) #-} -instance HasSetter IORef where- ($=) = writeIORef+instance Storable a => HasSetter (Ptr a) a where+ p $= a = liftIO $ poke p a+ {-# INLINE ($=) #-} --- | A concrete implementation of a write-only state variable, carrying an IO--- action to write the new value.-newtype SettableStateVar a = SettableStateVar (a -> IO ())+instance HasSetter (IORef a) a where+ p $= a = liftIO $ writeIORef p a+ {-# INLINE ($=) #-} -instance HasSetter SettableStateVar where- ($=) (SettableStateVar s) a = s a+instance HasSetter (TVar a) a where+ p $= a = liftIO $ atomically $ writeTVar p a+ {-# INLINE ($=) #-} --- instance Contravariant SettableStateVar where--- contramap f (SettableStateVar s) = SettableStateVar (s . f)+--------------------------------------------------------------------+-- * HasUpdate+-------------------------------------------------------------------- --- | Construct a 'SettableStateVar' from an IO action.-makeSettableStateVar :: (a -> IO ()) -> SettableStateVar a-makeSettableStateVar = SettableStateVar+infixr 2 $~, $~! ---------------------------------------------------------------------------------+class HasSetter t a => HasUpdate t a b | t -> a b where+ -- | Transform the contents of a state variable with a given funtion.+ ($~) :: MonadIO m => t -> (a -> b) -> m ()+#if USE_DEFAULT_SIGNATURES+ default ($~) :: (MonadIO m, a ~ b, HasGetter t a, HasSetter t a) => t -> (a -> b) -> m ()+ ($~) = defaultUpdate+#endif+ -- | This is a variant of '$~' which is strict in the transformed value.+ ($~!) :: MonadIO m => t -> (a -> b) -> m ()+#if USE_DEFAULT_SIGNATURES+ default ($~!) :: (MonadIO m, a ~ b, HasGetter t a, HasSetter t a) => t -> (a -> b) -> m ()+ ($~!) = defaultUpdateStrict+#endif --- | 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 a =- StateVar (GettableStateVar a) (SettableStateVar a)+defaultUpdate :: (MonadIO m, a ~ b, HasGetter t a, HasSetter t a) => t -> (a -> b) -> m ()+defaultUpdate r f = liftIO $ do+ a <- get r+ r $= f a -instance HasGetter StateVar where- get (StateVar g _) = get g+defaultUpdateStrict :: (MonadIO m, a ~ b, HasGetter t a, HasSetter t a) => t -> (a -> b) -> m ()+defaultUpdateStrict r f = liftIO $ do+ a <- get r+ r $=! f a -instance HasSetter StateVar where- ($=) (StateVar _ s) a = s $= a+instance HasUpdate (StateVar a) a a where+ ($~) = defaultUpdate+ ($~!) = defaultUpdateStrict --- | Construct a 'StateVar' from two IO actions, one for reading and one for--- writing.-makeStateVar :: IO a -> (a -> IO ()) -> StateVar a-makeStateVar g s = StateVar (makeGettableStateVar g) (makeSettableStateVar s)+instance Storable a => HasUpdate (Ptr a) a a where+ ($~) = defaultUpdate+ ($~!) = defaultUpdateStrict ---------------------------------------------------------------------------------+instance HasUpdate (IORef a) a a where+ r $~ f = liftIO $ atomicModifyIORef r $ \a -> (f a,())+#if __GLASGOW_HASKELL__ >= 706+ r $~! f = liftIO $ atomicModifyIORef' r $ \a -> (f a,())+#else+ r $~! f = liftIO $ do+ s <- atomicModifyIORef r $ \a -> let s = f a in (s, s)+ s `seq` return ()+#endif --- | A modificator convenience function, transforming the contents of a state--- variable with a given funtion.+instance HasUpdate (TVar a) a a where+ r $~ f = liftIO $ atomically $ do+ a <- readTVar r+ writeTVar r (f a)+ r $~! f = liftIO $ atomically $ do+ a <- readTVar r+ writeTVar r $! f a -($~) :: (HasGetter v, HasSetter v) => v a -> (a -> a) -> IO ()-v $~ f = do- x <- get v- v $= f x+--------------------------------------------------------------------+-- * HasGetter+-------------------------------------------------------------------- --- | A variant of '$=' which is strict in the value to be set.-($=!) :: HasSetter s => s a -> a -> IO ()-v $=! x = x `seq` v $= x+class HasGetter t a | t -> a where+ get :: MonadIO m => t -> m a --- | A variant of '$~' which is strict in the transformed value.-($~!) :: (HasGetter v, HasSetter v) => v a -> (a -> a) -> IO ()-v $~! f = do- x <- get v- v $=! f x+instance HasGetter (StateVar a) a where+ get (StateVar g _) = liftIO g+ {-# INLINE get #-}++instance HasGetter (TVar a) a where+ get = liftIO . atomically . readTVar+ {-# INLINE get #-}++instance HasGetter (IO a) a where+ get = liftIO+ {-# INLINE get #-}++instance HasGetter (STM a) a where+ get = liftIO . atomically+ {-# INLINE get #-}++instance Storable a => HasGetter (Ptr a) a where+ get = liftIO . peek+ {-# INLINE get #-}++instance HasGetter (IORef a) a where+ get = liftIO . readIORef+ {-# INLINE get #-}