{-# LANGUAGE CPP #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE MultiParamTypeClasses #-} import Safe import Control.Monad.StateVar import Control.Concurrent.STM import Data.IORef import Data.STRef import qualified Data.STRef.Lazy as L import Control.Exception import Control.Monad.ST import qualified Control.Monad.ST.Lazy as L -- Functional dependency needed so tryErrorCall's callback can refer to an -- outside var. class (HasGet m v, HasPut m v, Monad m) => TestStateVar m v | m -> v where tryErrorCall :: Maybe (m a -> m (Either ErrorCall a)) instance TestStateVar IO IORef where tryErrorCall = Just try instance TestStateVar STM TVar where tryErrorCall = Just trySTM instance TestStateVar (ST s) (STRef s) where tryErrorCall = Nothing instance TestStateVar (L.ST s) (STRef s) where tryErrorCall = Nothing trySTM :: Exception e => STM a -> STM (Either e a) trySTM a = catchSTM (a >>= \v -> return (Right v)) (\e -> return (Left e)) testStateVar :: TestStateVar m v => v Int -> m () testStateVar var = do 0 <- get var put var 1 1 <- get var var $= 2 2 <- get var modify var (+1) 3 <- get var modify' var (+1) 4 <- get var var $~ (+1) 5 <- get var var $~! (+1) 6 <- get var 6 <- swap var 7 7 <- get var case tryErrorCall of Nothing -> return () Just tryE -> do Left (ErrorCall _) <- tryE $ do put' var undefined 7 <- get var -- These tests assume the var may contain 'undefined'. modify var (\_ -> undefined) modify var undefined modify var (+1) _ <- get var Left (ErrorCall _) <- tryE $ do modify' var (+1) return () -- testIORef and testSTRef just make sure casual usage type check without -- confusing ambiguities. testIORef :: IO () testIORef = do var <- newIORef (5 :: Int) 5 <- get var put var 6 6 <- get var modify var (+3) 9 <- get var return () testSTRef :: IO () testSTRef = do 9 <- return $ runST $ do var <- newSTRef (5 :: Int) 5 <- get var put var 6 6 <- get var modify var (+3) get var return () main :: IO () main = do testSafe newIORef 0 >>= testStateVar atomically $ newTVar 0 >>= testStateVar () <- return $ runST $ newSTRef 0 >>= testStateVar () <- return $ L.runST $ L.newSTRef 0 >>= testStateVar testIORef testSTRef putStrLn "Passed."