{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, GADTs #-} module Data.StateRef.Types where -- |A simple reference type, hiding the complexity of all these type classes, -- since most of the time the only thing you care about is that you want a reference. -- The full complexity is still there, though, so FFI types or other reference-like -- things can still be made into 'Ref's. data Ref m a where Ref :: ModifyRef sr m a => !sr -> Ref m a class WriteRef sr m a | sr -> a where -- |Replace the existing value of the given reference with the provided value. writeReference :: sr -> a -> m () class ReadRef sr m a | sr -> a where -- |Get the current value referenced by the given state reference. readReference :: sr -> m a class (ReadRef sr m a, WriteRef sr m a) => ModifyRef sr m a | sr -> a where -- |Atomically modify the contents of a reference. This is -- implemented in a separate class (rather than a function with -- context (ReadRef sr m a, WriteRef sr m a)) because in most -- cases the default implementation cannot act atomically. atomicModifyReference :: sr -> (a -> (a,b)) -> m b -- |Same thing, but don't thread out the extra return. Could perhaps -- be implemented slightly more efficiently than 'atomicModifyReference' in many cases. -- Note that implementations are expected to be atomic, if at all possible, -- but not strictly required to be. modifyReference :: sr -> (a -> a) -> m () -- |Default implementation of atomicModifyReference in terms of readReference and writeReference defaultAtomicModifyReference ref f = do x <- readReference ref let (x', b) = f x writeReference ref x' return b -- |Default implementation of modifyReference in terms of readReference and writeReference defaultModifyReference ref f = do x <- readReference ref let x' = f x writeReference ref x' return () class NewRef sr m a | sr -> a where -- |Construct a new reference to the provided value. newReference :: a -> m sr class HasRef m where -- |Construct a new mutable reference (of an unspecified implementation type) containing the provided value. newRef :: a -> m (Ref m a)