io-classes 1.8.0.1 → 1.9.0.0
raw patch · 47 files changed
+3193/−3034 lines, 47 filesdep ~time
Dependency ranges changed: time
Files
- CHANGELOG.md +23/−3
- io-classes.cabal +5/−3
- io-classes/Control/Concurrent/Class/MonadMVar.hs +234/−0
- io-classes/Control/Concurrent/Class/MonadSTM.hs +12/−0
- io-classes/Control/Concurrent/Class/MonadSTM/TArray.hs +7/−0
- io-classes/Control/Concurrent/Class/MonadSTM/TBQueue.hs +28/−0
- io-classes/Control/Concurrent/Class/MonadSTM/TChan.hs +26/−0
- io-classes/Control/Concurrent/Class/MonadSTM/TMVar.hs +31/−0
- io-classes/Control/Concurrent/Class/MonadSTM/TQueue.hs +26/−0
- io-classes/Control/Concurrent/Class/MonadSTM/TSem.hs +20/−0
- io-classes/Control/Concurrent/Class/MonadSTM/TVar.hs +28/−0
- io-classes/Control/Monad/Class/MonadAsync.hs +616/−0
- io-classes/Control/Monad/Class/MonadEventlog.hs +34/−0
- io-classes/Control/Monad/Class/MonadFork.hs +95/−0
- io-classes/Control/Monad/Class/MonadST.hs +57/−0
- io-classes/Control/Monad/Class/MonadSTM.hs +29/−0
- io-classes/Control/Monad/Class/MonadSTM/Internal.hs +1309/−0
- io-classes/Control/Monad/Class/MonadSay.hs +13/−0
- io-classes/Control/Monad/Class/MonadTest.hs +17/−0
- io-classes/Control/Monad/Class/MonadThrow.hs +328/−0
- io-classes/Control/Monad/Class/MonadTime.hs +55/−0
- io-classes/Control/Monad/Class/MonadTimer.hs +62/−0
- io-classes/Control/Monad/Class/MonadUnique.hs +48/−0
- mtl/Control/Monad/Class/MonadUnique/Trans.hs +40/−0
- si-timers/src/Control/Monad/Class/MonadTime/SI.hs +6/−2
- si-timers/src/Control/Monad/Class/MonadTimer/SI.hs +24/−0
- si-timers/test/Test/MonadTimer.hs +20/−0
- src/Control/Concurrent/Class/MonadMVar.hs +0/−234
- src/Control/Concurrent/Class/MonadSTM.hs +0/−14
- src/Control/Concurrent/Class/MonadSTM/TArray.hs +0/−7
- src/Control/Concurrent/Class/MonadSTM/TBQueue.hs +0/−28
- src/Control/Concurrent/Class/MonadSTM/TChan.hs +0/−26
- src/Control/Concurrent/Class/MonadSTM/TMVar.hs +0/−31
- src/Control/Concurrent/Class/MonadSTM/TQueue.hs +0/−26
- src/Control/Concurrent/Class/MonadSTM/TSem.hs +0/−20
- src/Control/Concurrent/Class/MonadSTM/TVar.hs +0/−28
- src/Control/Monad/Class/MonadAsync.hs +0/−616
- src/Control/Monad/Class/MonadEventlog.hs +0/−34
- src/Control/Monad/Class/MonadFork.hs +0/−95
- src/Control/Monad/Class/MonadST.hs +0/−57
- src/Control/Monad/Class/MonadSTM.hs +0/−29
- src/Control/Monad/Class/MonadSTM/Internal.hs +0/−1306
- src/Control/Monad/Class/MonadSay.hs +0/−13
- src/Control/Monad/Class/MonadTest.hs +0/−17
- src/Control/Monad/Class/MonadThrow.hs +0/−328
- src/Control/Monad/Class/MonadTime.hs +0/−55
- src/Control/Monad/Class/MonadTimer.hs +0/−62
CHANGELOG.md view
@@ -1,7 +1,27 @@ # Revsion history of io-classes -### 1.8.0.1+## next release +### Breaking changes++### Non-breaking changes++## 1.9.0.0++### Breaking changes++* Changed `Time` show instance, which now is designed for pasting+* counterexamples from terminal to an editor.++### Non-breaking changes++* Improved performance of `tryReadTBQueueDefault`.+* Added module `Control.Monad.Class.MonadUnique` generalising `Data.Unique`.+* mtl: Added module `Control.Monad.Class.MonadUnique.Trans` providing monad transformer instances for `MonadUnique`.+* Added `roundDiffTimeToMicroseconds` utility function to `si-timers` package (in the `MonadTimer.SI` module).++## 1.8.0.1+ * Added support for `ghc-9.2`. ### 1.8.0.0@@ -25,13 +45,13 @@ type classes. * Support ghc-9.12 -### 1.7.0.0+## 1.7.0.0 ### Breaking changes * Renamed `io-classes:io-classes-mtl` as `io-classes:mtl`. -### 1.6.0.0+## 1.6.0.0 ### Breaking changes
io-classes.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.4 name: io-classes-version: 1.8.0.1+version: 1.9.0.0 synopsis: Type classes for concurrency with STM, ST and timing description: IO Monad class hierarchy compatible with:@@ -63,7 +63,7 @@ library import: warnings- hs-source-dirs: src+ hs-source-dirs: io-classes -- At this experiment/prototype stage everything is exposed. -- This has to be tidied up once the design becomes clear.@@ -87,6 +87,7 @@ Control.Monad.Class.MonadTime Control.Monad.Class.MonadTimer Control.Monad.Class.MonadTest+ Control.Monad.Class.MonadUnique default-language: GHC2021 default-extensions: LambdaCase build-depends: base >=4.16 && <4.22,@@ -96,7 +97,7 @@ mtl >=2.2 && <2.4, primitive >= 0.7 && <0.11, stm >=2.5 && <2.5.2 || ^>=2.5.3,- time >=1.9.1 && <1.13+ time >=1.9.1 && <1.16 if impl(ghc >= 9.10) build-depends: ghc-internal @@ -174,6 +175,7 @@ , Control.Monad.Class.MonadTime.SI.Trans , Control.Monad.Class.MonadTimer.Trans , Control.Monad.Class.MonadTimer.SI.Trans+ , Control.Monad.Class.MonadUnique.Trans build-depends: base, array, mtl,
+ io-classes/Control/Concurrent/Class/MonadMVar.hs view
@@ -0,0 +1,234 @@+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE TypeFamilyDependencies #-}++module Control.Concurrent.Class.MonadMVar+ ( MonadMVar (..)+ -- * non-standard extensions+ , MonadInspectMVar (..)+ , MonadTraceMVar (..)+ , MonadLabelledMVar (..)+ ) where++import Control.Concurrent.MVar qualified as IO+import Control.Monad.Class.MonadThrow++import Control.Monad.Reader (ReaderT (..))+import Control.Monad.Trans (lift)++import Control.Concurrent.Class.MonadSTM (TraceValue)+import Data.Kind (Type)+++class Monad m => MonadMVar m where+ {-# MINIMAL newEmptyMVar,+ takeMVar, tryTakeMVar,+ putMVar, tryPutMVar,+ readMVar, tryReadMVar,+ isEmptyMVar #-}++ type MVar m :: Type -> Type++ -- | See 'IO.newEmptyMVar'.+ newEmptyMVar :: m (MVar m a)+ -- | See 'IO.takeMVar'.+ takeMVar :: MVar m a -> m a+ -- | See 'IO.putMVar'.+ putMVar :: MVar m a -> a -> m ()+ -- | See 'IO.tryTakeMVar'.+ tryTakeMVar :: MVar m a -> m (Maybe a)+ -- | See 'IO.tryPutMVar'.+ tryPutMVar :: MVar m a -> a -> m Bool+ -- | See 'IO.isEmptyMVar'.+ isEmptyMVar :: MVar m a -> m Bool++ -- methods with a default implementation+ -- | See 'IO.newMVar'.+ newMVar :: a -> m (MVar m a)+ -- | See 'IO.readMVar'.+ readMVar :: MVar m a -> m a+ -- | See 'IO.tryReadMVar'.+ tryReadMVar :: MVar m a -> m (Maybe a)+ -- | See 'IO.swapMVar'.+ swapMVar :: MVar m a -> a -> m a+ -- | See 'IO.withMVar'.+ withMVar :: MVar m a -> (a -> m b) -> m b+ -- | See 'IO.withMVarMasked'.+ withMVarMasked :: MVar m a -> (a -> m b) -> m b+ -- | See 'IO.modifyMVar_'.+ modifyMVar_ :: MVar m a -> (a -> m a) -> m ()+ -- | See 'IO.modifyMVar'.+ modifyMVar :: MVar m a -> (a -> m (a, b)) -> m b+ -- | See 'IO.modifyMVarMasked_'.+ modifyMVarMasked_ :: MVar m a -> (a -> m a) -> m ()+ -- | See 'IO.modifyMVarMasked'.+ modifyMVarMasked :: MVar m a -> (a -> m (a,b)) -> m b++ default newMVar :: a -> m (MVar m a)+ newMVar a = do+ v <- newEmptyMVar+ putMVar v a+ return v+ {-# INLINE newMVar #-}++ default swapMVar :: MonadMask m => MVar m a -> a -> m a+ swapMVar mvar new =+ mask_ $ do+ old <- takeMVar mvar+ putMVar mvar new+ return old+ {-# INLINE swapMVar #-}++ default withMVar :: MonadMask m => MVar m a -> (a -> m b) -> m b+ withMVar m io =+ mask $ \restore -> do+ a <- takeMVar m+ b <- restore (io a) `onException` putMVar m a+ putMVar m a+ return b+ {-# INLINE withMVar #-}++ default withMVarMasked :: MonadMask m => MVar m a -> (a -> m b) -> m b+ withMVarMasked m io =+ mask_ $ do+ a <- takeMVar m+ b <- io a `onException` putMVar m a+ putMVar m a+ return b+ {-# INLINE withMVarMasked #-}++ default modifyMVar_ :: MonadMask m => MVar m a -> (a -> m a) -> m ()+ modifyMVar_ m io =+ mask $ \restore -> do+ a <- takeMVar m+ a' <- restore (io a) `onException` putMVar m a+ putMVar m a'+ {-# INLINE modifyMVar_ #-}++ default modifyMVar :: (MonadMask m, MonadEvaluate m)+ => MVar m a -> (a -> m (a,b)) -> m b+ modifyMVar m io =+ mask $ \restore -> do+ a <- takeMVar m+ (a',b) <- restore (io a >>= evaluate) `onException` putMVar m a+ putMVar m a'+ return b+ {-# INLINE modifyMVar #-}++ default modifyMVarMasked_ :: MonadMask m => MVar m a -> (a -> m a) -> m ()+ modifyMVarMasked_ m io =+ mask_ $ do+ a <- takeMVar m+ a' <- io a `onException` putMVar m a+ putMVar m a'+ {-# INLINE modifyMVarMasked_ #-}++ default modifyMVarMasked :: (MonadMask m, MonadEvaluate m)+ => MVar m a -> (a -> m (a,b)) -> m b+ modifyMVarMasked m io =+ mask_ $ do+ a <- takeMVar m+ (a',b) <- (io a >>= evaluate) `onException` putMVar m a+ putMVar m a'+ return b+ {-# INLINE modifyMVarMasked #-}++--+-- IO instance+--++instance MonadMVar IO where+ type MVar IO = IO.MVar+ newEmptyMVar = IO.newEmptyMVar+ newMVar = IO.newMVar+ takeMVar = IO.takeMVar+ putMVar = IO.putMVar+ readMVar = IO.readMVar+ swapMVar = IO.swapMVar+ tryTakeMVar = IO.tryTakeMVar+ tryPutMVar = IO.tryPutMVar+ tryReadMVar = IO.tryReadMVar+ isEmptyMVar = IO.isEmptyMVar+ withMVar = IO.withMVar+ withMVarMasked = IO.withMVarMasked+ modifyMVar_ = IO.modifyMVar_+ modifyMVar = IO.modifyMVar+ modifyMVarMasked_ = IO.modifyMVarMasked_+ modifyMVarMasked = IO.modifyMVarMasked++--+-- ReaderT instance+--++newtype WrappedMVar r (m :: Type -> Type) a = WrappedMVar { unwrapMVar :: MVar m a }++instance ( MonadMask m+ , MonadMVar m+ ) => MonadMVar (ReaderT r m) where+ type MVar (ReaderT r m) = WrappedMVar r m+ newEmptyMVar = WrappedMVar <$> lift newEmptyMVar+ newMVar = fmap WrappedMVar . lift . newMVar+ takeMVar = lift . takeMVar . unwrapMVar+ putMVar = lift .: (putMVar . unwrapMVar)+ readMVar = lift . readMVar . unwrapMVar+ tryReadMVar = lift . tryReadMVar . unwrapMVar+ swapMVar = lift .: (swapMVar . unwrapMVar)+ tryTakeMVar = lift . tryTakeMVar . unwrapMVar+ tryPutMVar = lift .: (tryPutMVar . unwrapMVar)+ isEmptyMVar = lift . isEmptyMVar . unwrapMVar+ withMVar (WrappedMVar v) f = ReaderT $ \r ->+ withMVar v (\a -> runReaderT (f a) r)+ withMVarMasked (WrappedMVar v) f = ReaderT $ \r ->+ withMVarMasked v (\a -> runReaderT (f a) r)+ modifyMVar_ (WrappedMVar v) f = ReaderT $ \r ->+ modifyMVar_ v (\a -> runReaderT (f a) r)+ modifyMVar (WrappedMVar v) f = ReaderT $ \r ->+ modifyMVar v (\a -> runReaderT (f a) r)+ modifyMVarMasked_ (WrappedMVar v) f = ReaderT $ \r ->+ modifyMVarMasked_ v (\a -> runReaderT (f a) r)+ modifyMVarMasked (WrappedMVar v) f = ReaderT $ \r ->+ modifyMVarMasked v (\a -> runReaderT (f a) r)++--+-- MonadInspectMVar+--++-- | This type class is intended for+-- ['io-sim'](https://hackage.haskell.org/package/io-sim), where one might want+-- to access an 'MVar' in the underlying 'ST' monad.+class (MonadMVar m, Monad (InspectMVarMonad m)) => MonadInspectMVar m where+ type InspectMVarMonad m :: Type -> Type+ -- | Return the value of an 'MVar' as an 'InspectMVarMonad' computation. Can+ -- be 'Nothing' if the 'MVar' is empty.+ inspectMVar :: proxy m -> MVar m a -> InspectMVarMonad m (Maybe a)++instance MonadInspectMVar IO where+ type InspectMVarMonad IO = IO+ inspectMVar _ = tryReadMVar++class MonadTraceMVar m where+ traceMVarIO :: proxy+ -> MVar m a+ -> (Maybe (Maybe a) -> Maybe a -> InspectMVarMonad m TraceValue)+ -> m ()++instance MonadTraceMVar IO where+ traceMVarIO = \_ _ _ -> pure ()++-- | Labelled `MVar`s+--+-- The `IO` instances is no-op, the `IOSim` instance enhances simulation trace.+-- This is very useful when analysing low lever concurrency issues (e.g.+-- deadlocks, livelocks etc).+class MonadMVar m+ => MonadLabelledMVar m where+ -- | Name an `MVar`+ labelMVar :: MVar m a -> String -> m ()++instance MonadLabelledMVar IO where+ labelMVar = \_ _ -> pure ()+--+-- Utilities+--++(.:) :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)+(f .: g) x y = f (g x y)
+ io-classes/Control/Concurrent/Class/MonadSTM.hs view
@@ -0,0 +1,12 @@+-- | This module corresponds to "Control.Concurrent.STM" in "stm" package+--+module Control.Concurrent.Class.MonadSTM (module STM) where++import Control.Concurrent.Class.MonadSTM.TArray as STM+import Control.Concurrent.Class.MonadSTM.TBQueue as STM+import Control.Concurrent.Class.MonadSTM.TChan as STM+import Control.Concurrent.Class.MonadSTM.TMVar as STM+import Control.Concurrent.Class.MonadSTM.TQueue as STM+import Control.Concurrent.Class.MonadSTM.TVar as STM+import Control.Monad.Class.MonadSTM as STM+
+ io-classes/Control/Concurrent/Class/MonadSTM/TArray.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE ExplicitNamespaces #-}++-- | This module corresponds to `Control.Concurrent.STM.TArray` in "stm" package+--+module Control.Concurrent.Class.MonadSTM.TArray (type TArray) where++import Control.Monad.Class.MonadSTM.Internal
+ io-classes/Control/Concurrent/Class/MonadSTM/TBQueue.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE ExplicitNamespaces #-}++-- | This module corresponds to `Control.Concurrent.STM.TVar` in "stm" package+--+module Control.Concurrent.Class.MonadSTM.TBQueue+ ( -- * MonadSTM+ type TBQueue+ , newTBQueue+ , newTBQueueIO+ , readTBQueue+ , tryReadTBQueue+ , peekTBQueue+ , tryPeekTBQueue+ , flushTBQueue+ , writeTBQueue+ , lengthTBQueue+ , isEmptyTBQueue+ , isFullTBQueue+ , unGetTBQueue+ -- * MonadLabelledSTM+ , labelTBQueue+ , labelTBQueueIO+ -- * MonadTraceSTM+ , traceTBQueue+ , traceTBQueueIO+ ) where++import Control.Monad.Class.MonadSTM.Internal
+ io-classes/Control/Concurrent/Class/MonadSTM/TChan.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE ExplicitNamespaces #-}++-- | This module corresponds to `Control.Concurrent.STM.TChan` in "stm" package+--+module Control.Concurrent.Class.MonadSTM.TChan+ ( -- * MonadSTM+ -- ** TChans+ type TChan+ -- * Construction+ , newTChan+ , newBroadcastTChan+ , newTChanIO+ , newBroadcastTChanIO+ , dupTChan+ , cloneTChan+ -- ** Reading and writing+ , readTChan+ , tryReadTChan+ , peekTChan+ , tryPeekTChan+ , writeTChan+ , unGetTChan+ , isEmptyTChan+ ) where++import Control.Monad.Class.MonadSTM.Internal
+ io-classes/Control/Concurrent/Class/MonadSTM/TMVar.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE ExplicitNamespaces #-}++-- | This module corresponds to `Control.Concurrent.STM.TMVar` in "stm" package+--+module Control.Concurrent.Class.MonadSTM.TMVar+ ( -- * MonadSTM+ type TMVar+ , newTMVar+ , newEmptyTMVar+ , newTMVarIO+ , newEmptyTMVarIO+ , takeTMVar+ , tryTakeTMVar+ , putTMVar+ , tryPutTMVar+ , readTMVar+ , tryReadTMVar+ , swapTMVar+ , writeTMVar+ , isEmptyTMVar+ -- * MonadLabelledSTM+ , labelTMVar+ , labelTMVarIO+ -- * MonadTraceSTM+ , traceTMVar+ , traceTMVarIO+ , debugTraceTMVar+ , debugTraceTMVarIO+ ) where++import Control.Monad.Class.MonadSTM.Internal
+ io-classes/Control/Concurrent/Class/MonadSTM/TQueue.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE ExplicitNamespaces #-}++-- | This module corresponds to `Control.Concurrent.STM.TQueue` in "stm" package+--+module Control.Concurrent.Class.MonadSTM.TQueue+ ( -- * MonadSTM+ type TQueue+ , newTQueue+ , newTQueueIO+ , readTQueue+ , tryReadTQueue+ , peekTQueue+ , tryPeekTQueue+ , flushTQueue+ , writeTQueue+ , unGetTQueue+ , isEmptyTQueue+ -- * MonadLabelledSTM+ , labelTQueue+ , labelTQueueIO+ -- * MonadTraceSTM+ , traceTQueue+ , traceTQueueIO+ ) where++import Control.Monad.Class.MonadSTM.Internal
+ io-classes/Control/Concurrent/Class/MonadSTM/TSem.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE ExplicitNamespaces #-}++-- | This module corresponds to `Control.Concurrent.STM.TSem` in "stm" package+--+module Control.Concurrent.Class.MonadSTM.TSem+ ( -- * MonadSTM+ type TSem+ , newTSem+ , waitTSem+ , signalTSem+ , signalTSemN+ -- * MonadLabelledSTM+ , labelTSem+ , labelTSemIO+ -- * MonadTraceSTM+ , traceTSem+ , traceTSemIO+ ) where++import Control.Monad.Class.MonadSTM.Internal
+ io-classes/Control/Concurrent/Class/MonadSTM/TVar.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE ExplicitNamespaces #-}++-- | This module corresponds to `Control.Concurrent.STM.TVar` in "stm" package+--+module Control.Concurrent.Class.MonadSTM.TVar+ ( -- * MonadSTM+ type TVar+ , newTVar+ , newTVarIO+ , readTVar+ , readTVarIO+ , writeTVar+ , modifyTVar+ , modifyTVar'+ , stateTVar+ , swapTVar+ , check+ -- * MonadLabelSTM+ , labelTVar+ , labelTVarIO+ -- * MonadTraceSTM+ , traceTVar+ , traceTVarIO+ , debugTraceTVar+ , debugTraceTVarIO+ ) where++import Control.Monad.Class.MonadSTM.Internal
+ io-classes/Control/Monad/Class/MonadAsync.hs view
@@ -0,0 +1,616 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE TypeFamilyDependencies #-}+-- MonadAsync's ReaderT instance is undecidable.+{-# LANGUAGE UndecidableInstances #-}++-- | <https://hackage.haskell.org/package/async async> API compatible with both+-- 'IO' and <https://hackage.haskell.org/package/io-sim IOSim>.+--+module Control.Monad.Class.MonadAsync+ ( MonadAsync (..)+ , AsyncCancelled (..)+ , ExceptionInLinkedThread (..)+ , link+ , linkOnly+ , link2+ , link2Only+ , mapConcurrently+ , forConcurrently+ , mapConcurrently_+ , forConcurrently_+ , replicateConcurrently+ , replicateConcurrently_+ , Concurrently (..)+ ) where++import Prelude hiding (read)++#if MIN_VERSION_base(4,18,0)+import Control.Applicative (Alternative (..))+#else+import Control.Applicative (Alternative (..), liftA2)+#endif+import Control.Monad (forever)+import Control.Monad.Class.MonadFork+import Control.Monad.Class.MonadSTM+import Control.Monad.Class.MonadThrow+import Control.Monad.Class.MonadTimer++import Control.Monad.Reader (ReaderT (..))+import Control.Monad.Trans (lift)++import Control.Concurrent.Async (AsyncCancelled (..))+import Control.Concurrent.Async qualified as Async+import Control.Exception qualified as E++import Data.Bifunctor (first)+import Data.Foldable (fold)+import Data.Functor (void)+import Data.Kind (Type)++class ( MonadSTM m+ , MonadThread m+ ) => MonadAsync m where++ {-# MINIMAL async, asyncBound, asyncOn, asyncThreadId, cancel, cancelWith,+ asyncWithUnmask, asyncOnWithUnmask, waitCatchSTM, pollSTM #-}++ -- | An asynchronous action+ --+ -- See 'Async.Async'.+ type Async m = (async :: Type -> Type) | async -> m++ -- | See 'Async.async'.+ async :: m a -> m (Async m a)+ -- | See 'Async.asyncBound'.+ asyncBound :: m a -> m (Async m a)+ -- | See 'Async.asyncOn'.+ asyncOn :: Int -> m a -> m (Async m a)+ -- | See 'Async.asyncThreadId'.+ asyncThreadId :: Async m a -> ThreadId m+ -- | See 'Async.withAsync'.+ withAsync :: m a -> (Async m a -> m b) -> m b+ -- | See 'Async.withAsyncBound'.+ withAsyncBound :: m a -> (Async m a -> m b) -> m b+ -- | See 'Async.withAsyncOn'.+ withAsyncOn :: Int -> m a -> (Async m a -> m b) -> m b++ -- | See 'Async.waitSTM'.+ waitSTM :: Async m a -> STM m a+ -- | See 'Async.pollSTM'.+ pollSTM :: Async m a -> STM m (Maybe (Either SomeException a))+ -- | See 'Async.waitCatchSTM'.+ waitCatchSTM :: Async m a -> STM m (Either SomeException a)++ default waitSTM :: MonadThrow (STM m) => Async m a -> STM m a+ waitSTM action = waitCatchSTM action >>= either throwSTM return++ -- | See 'Async.waitAnySTM'.+ waitAnySTM :: [Async m a] -> STM m (Async m a, a)+ -- | See 'Async.waitAnyCatchSTM'.+ waitAnyCatchSTM :: [Async m a] -> STM m (Async m a, Either SomeException a)+ -- | See 'Async.waitEitherSTM'.+ waitEitherSTM :: Async m a -> Async m b -> STM m (Either a b)+ -- | See 'Async.waitEitherSTM_'.+ waitEitherSTM_ :: Async m a -> Async m b -> STM m ()+ -- | See 'Async.waitEitherCatchSTM'.+ waitEitherCatchSTM :: Async m a -> Async m b+ -> STM m (Either (Either SomeException a)+ (Either SomeException b))+ -- | See 'Async.waitBothSTM'.+ waitBothSTM :: Async m a -> Async m b -> STM m (a, b)++ -- | See 'Async.wait'.+ wait :: Async m a -> m a+ -- | See 'Async.poll'.+ poll :: Async m a -> m (Maybe (Either SomeException a))+ -- | See 'Async.waitCatch'.+ waitCatch :: Async m a -> m (Either SomeException a)+ -- | See 'Async.cancel'.+ cancel :: Async m a -> m ()+ -- | See 'Async.cancelWith'.+ cancelWith :: Exception e => Async m a -> e -> m ()+ -- | See 'Async.uninterruptibleCancel'.+ uninterruptibleCancel :: Async m a -> m ()++ -- | See 'Async.waitAny'.+ waitAny :: [Async m a] -> m (Async m a, a)+ -- | See 'Async.waitAnyCatch'.+ waitAnyCatch :: [Async m a] -> m (Async m a, Either SomeException a)+ -- | See 'Async.waitAnyCancel'.+ waitAnyCancel :: [Async m a] -> m (Async m a, a)+ -- | See 'Async.waitAnyCatchCancel'.+ waitAnyCatchCancel :: [Async m a] -> m (Async m a, Either SomeException a)+ -- | See 'Async.waitEither'.+ waitEither :: Async m a -> Async m b -> m (Either a b)++ default waitAnySTM :: MonadThrow (STM m) => [Async m a] -> STM m (Async m a, a)+ default waitEitherSTM :: MonadThrow (STM m) => Async m a -> Async m b -> STM m (Either a b)+ default waitEitherSTM_ :: MonadThrow (STM m) => Async m a -> Async m b -> STM m ()+ default waitBothSTM :: MonadThrow (STM m) => Async m a -> Async m b -> STM m (a, b)++ waitAnySTM as =+ foldr orElse retry $+ map (\a -> do r <- waitSTM a; return (a, r)) as++ waitAnyCatchSTM as =+ foldr orElse retry $+ map (\a -> do r <- waitCatchSTM a; return (a, r)) as++ waitEitherSTM left right =+ (Left <$> waitSTM left)+ `orElse`+ (Right <$> waitSTM right)++ waitEitherSTM_ left right =+ (void $ waitSTM left)+ `orElse`+ (void $ waitSTM right)++ waitEitherCatchSTM left right =+ (Left <$> waitCatchSTM left)+ `orElse`+ (Right <$> waitCatchSTM right)++ waitBothSTM left right = do+ a <- waitSTM left+ `orElse`+ (waitSTM right >> retry)+ b <- waitSTM right+ return (a,b)++ -- | Note, IO-based implementations should override the default+ -- implementation. See the @async@ package implementation and comments.+ -- <http://hackage.haskell.org/package/async-2.2.1/docs/src/Control.Concurrent.Async.html#waitEitherCatch>+ --+ -- See 'Async.waitEitherCatch'.+ waitEitherCatch :: Async m a -> Async m b -> m (Either (Either SomeException a)+ (Either SomeException b))+ -- | See 'Async.waitEitherCancel'.+ waitEitherCancel :: Async m a -> Async m b -> m (Either a b)+ -- | See 'Async.waitEitherCatchCancel'.+ waitEitherCatchCancel :: Async m a -> Async m b -> m (Either (Either SomeException a)+ (Either SomeException b))+ -- | See 'Async.waitEither_'.+ waitEither_ :: Async m a -> Async m b -> m ()+ -- | See 'Async.waitBoth'.+ waitBoth :: Async m a -> Async m b -> m (a, b)++ -- | See 'Async.race'.+ race :: m a -> m b -> m (Either a b)+ -- | See 'Async.race_'.+ race_ :: m a -> m b -> m ()+ -- | See 'Async.concurrently'.+ concurrently :: m a -> m b -> m (a,b)+ -- | See 'Async.concurrently_'.+ concurrently_ :: m a -> m b -> m ()++ -- | See 'Async.concurrently_'.+ asyncWithUnmask :: ((forall b . m b -> m b) -> m a) -> m (Async m a)+ -- | See 'Async.asyncOnWithUnmask'.+ asyncOnWithUnmask :: Int -> ((forall b . m b -> m b) -> m a) -> m (Async m a)+ -- | See 'Async.withAsyncWithUnmask'.+ withAsyncWithUnmask :: ((forall c. m c -> m c) -> m a) -> (Async m a -> m b) -> m b+ -- | See 'Async.withAsyncOnWithUnmask'.+ withAsyncOnWithUnmask :: Int -> ((forall c. m c -> m c) -> m a) -> (Async m a -> m b) -> m b++ -- | See 'Async.compareAsyncs'.+ compareAsyncs :: Async m a -> Async m b -> Ordering++ -- default implementations+ default withAsync :: MonadMask m => m a -> (Async m a -> m b) -> m b+ default withAsyncBound:: MonadMask m => m a -> (Async m a -> m b) -> m b+ default withAsyncOn :: MonadMask m => Int -> m a -> (Async m a -> m b) -> m b+ default withAsyncWithUnmask+ :: MonadMask m => ((forall c. m c -> m c) -> m a)+ -> (Async m a -> m b) -> m b+ default withAsyncOnWithUnmask+ :: MonadMask m => Int+ -> ((forall c. m c -> m c) -> m a)+ -> (Async m a -> m b) -> m b+ default uninterruptibleCancel+ :: MonadMask m => Async m a -> m ()+ default waitAnyCancel :: MonadThrow m => [Async m a] -> m (Async m a, a)+ default waitAnyCatchCancel :: MonadThrow m => [Async m a]+ -> m (Async m a, Either SomeException a)+ default waitEitherCancel :: MonadThrow m => Async m a -> Async m b+ -> m (Either a b)+ default waitEitherCatchCancel :: MonadThrow m => Async m a -> Async m b+ -> m (Either (Either SomeException a)+ (Either SomeException b))+ default compareAsyncs :: Ord (ThreadId m)+ => Async m a -> Async m b -> Ordering++ withAsync action inner = mask $ \restore -> do+ a <- async (restore action)+ restore (inner a)+ `finally` uninterruptibleCancel a++ withAsyncBound action inner = mask $ \restore -> do+ a <- asyncBound (restore action)+ restore (inner a)+ `finally` uninterruptibleCancel a++ withAsyncOn n action inner = mask $ \restore -> do+ a <- asyncOn n (restore action)+ restore (inner a)+ `finally` uninterruptibleCancel a+++ withAsyncWithUnmask action inner = mask $ \restore -> do+ a <- asyncWithUnmask action+ restore (inner a)+ `finally` uninterruptibleCancel a++ withAsyncOnWithUnmask n action inner = mask $ \restore -> do+ a <- asyncOnWithUnmask n action+ restore (inner a)+ `finally` uninterruptibleCancel a++ wait = atomically . waitSTM+ poll = atomically . pollSTM+ waitCatch = atomically . waitCatchSTM++ uninterruptibleCancel = uninterruptibleMask_ . cancel++ waitAny = atomically . waitAnySTM+ waitAnyCatch = atomically . waitAnyCatchSTM+ waitEither left right = atomically (waitEitherSTM left right)+ waitEither_ left right = atomically (waitEitherSTM_ left right)+ waitEitherCatch left right = atomically (waitEitherCatchSTM left right)+ waitBoth left right = atomically (waitBothSTM left right)++ waitAnyCancel asyncs =+ waitAny asyncs `finally` mapM_ cancel asyncs++ waitAnyCatchCancel asyncs =+ waitAnyCatch asyncs `finally` mapM_ cancel asyncs++ waitEitherCancel left right =+ waitEither left right `finally` (cancel left >> cancel right)++ waitEitherCatchCancel left right =+ waitEitherCatch left right `finally` (cancel left >> cancel right)++ race left right = withAsync left $ \a ->+ withAsync right $ \b ->+ waitEither a b++ race_ left right = withAsync left $ \a ->+ withAsync right $ \b ->+ waitEither_ a b++ concurrently left right = withAsync left $ \a ->+ withAsync right $ \b ->+ waitBoth a b++ concurrently_ left right = void $ concurrently left right++ compareAsyncs a b = asyncThreadId a `compare` asyncThreadId b++-- | Similar to 'Async.Concurrently' but which works for any 'MonadAsync'+-- instance.+--+newtype Concurrently m a = Concurrently { runConcurrently :: m a }++instance Functor m => Functor (Concurrently m) where+ fmap f (Concurrently ma) = Concurrently (fmap f ma)++instance MonadAsync m => Applicative (Concurrently m) where+ pure = Concurrently . pure++ Concurrently fn <*> Concurrently as =+ Concurrently $+ (\(f, a) -> f a)+ `fmap`+ concurrently fn as++instance ( MonadAsync m+ , MonadTimer m+ ) => Alternative (Concurrently m) where+ empty = Concurrently $ forever (threadDelay 86400)+ Concurrently as <|> Concurrently bs =+ Concurrently $ either id id <$> as `race` bs++instance ( Semigroup a+ , MonadAsync m+ ) => Semigroup (Concurrently m a) where+ (<>) = liftA2 (<>)++instance ( Monoid a+ , MonadAsync m+ ) => Monoid (Concurrently m a) where+ mempty = pure mempty+++-- | See 'Async.mapConcurrently'.+mapConcurrently :: (Traversable t, MonadAsync m) => (a -> m b) -> t a -> m (t b)+mapConcurrently f = runConcurrently . traverse (Concurrently . f)++-- | See 'Async.forConcurrently'.+forConcurrently :: (Traversable t, MonadAsync m) => t a -> (a -> m b) -> m (t b)+forConcurrently = flip mapConcurrently++-- | See 'Async.mapConcurrently_'.+mapConcurrently_ :: (Foldable f, MonadAsync m) => (a -> m b) -> f a -> m ()+mapConcurrently_ f = runConcurrently . foldMap (Concurrently . void . f)++-- | See 'Async.forConcurrently_'.+forConcurrently_ :: (Foldable f, MonadAsync m) => f a -> (a -> m b) -> m ()+forConcurrently_ = flip mapConcurrently_++-- | See 'Async.replicateConcurrently'.+replicateConcurrently :: MonadAsync m => Int -> m a -> m [a]+replicateConcurrently cnt = runConcurrently . sequenceA . replicate cnt . Concurrently++-- | See 'Async.replicateConcurrently_'.+replicateConcurrently_ :: MonadAsync m => Int -> m a -> m ()+replicateConcurrently_ cnt = runConcurrently . fold . replicate cnt . Concurrently . void+++--+-- Instance for IO uses the existing async library implementations+--++instance MonadAsync IO where++ type Async IO = Async.Async++ async = Async.async+ asyncBound = Async.asyncBound+ asyncOn = Async.asyncOn+ asyncThreadId = Async.asyncThreadId+ withAsync = Async.withAsync+ withAsyncBound = Async.withAsyncBound+ withAsyncOn = Async.withAsyncOn++ waitSTM = Async.waitSTM+ pollSTM = Async.pollSTM+ waitCatchSTM = Async.waitCatchSTM++ waitAnySTM = Async.waitAnySTM+ waitAnyCatchSTM = Async.waitAnyCatchSTM+ waitEitherSTM = Async.waitEitherSTM+ waitEitherSTM_ = Async.waitEitherSTM_+ waitEitherCatchSTM = Async.waitEitherCatchSTM+ waitBothSTM = Async.waitBothSTM++ wait = Async.wait+ poll = Async.poll+ waitCatch = Async.waitCatch+ cancel = Async.cancel+ cancelWith = Async.cancelWith+ uninterruptibleCancel = Async.uninterruptibleCancel++ waitAny = Async.waitAny+ waitAnyCatch = Async.waitAnyCatch+ waitAnyCancel = Async.waitAnyCancel+ waitAnyCatchCancel = Async.waitAnyCatchCancel+ waitEither = Async.waitEither+ waitEitherCatch = Async.waitEitherCatch+ waitEitherCancel = Async.waitEitherCancel+ waitEitherCatchCancel = Async.waitEitherCatchCancel+ waitEither_ = Async.waitEither_+ waitBoth = Async.waitBoth++ race = Async.race+ race_ = Async.race_+ concurrently = Async.concurrently+ concurrently_ = Async.concurrently_++ asyncWithUnmask = Async.asyncWithUnmask+ asyncOnWithUnmask = Async.asyncOnWithUnmask+ withAsyncWithUnmask = Async.withAsyncWithUnmask+ withAsyncOnWithUnmask = Async.withAsyncOnWithUnmask++ compareAsyncs = Async.compareAsyncs+++--+-- Linking+--+-- Adapted from "Control.Concurrent.Async"+--+-- We don't use the implementation of linking from 'Control.Concurrent.Async'+-- directly because if we /did/ use the real implementation, then the mock+-- implementation and the real implementation would not be able to throw the+-- same exception, because the exception type used by the real implementation+-- is+--+-- > data ExceptionInLinkedThread =+-- > forall a . ExceptionInLinkedThread (Async a) SomeException+--+-- containing a reference to the real 'Async' type.+--++-- | Exception from child thread re-raised in parent thread+--+-- We record the thread ID of the child thread as a 'String'. This avoids+-- an @m@ parameter in the type, which is important: 'ExceptionInLinkedThread'+-- must be an instance of 'Exception', requiring it to be 'Typeable'; if @m@+-- appeared in the type, we would require @m@ to be 'Typeable', which does not+-- work with with the simulator, as it would require a 'Typeable' constraint+-- on the @s@ parameter of 'IOSim'.+data ExceptionInLinkedThread = ExceptionInLinkedThread String SomeException++instance Show ExceptionInLinkedThread where+ showsPrec p (ExceptionInLinkedThread a e) =+ showParen (p >= 11) $+ showString "ExceptionInLinkedThread " .+ showsPrec 11 a .+ showString " " .+ showsPrec 11 e++instance Exception ExceptionInLinkedThread where+ fromException = E.asyncExceptionFromException+ toException = E.asyncExceptionToException++-- | Like 'Async.link'.+link :: (MonadAsync m, MonadFork m, MonadMask m)+ => Async m a -> m ()+link = linkOnly (not . isCancel)++-- | Like 'Async.linkOnly'.+linkOnly :: forall m a. (MonadAsync m, MonadFork m, MonadMask m)+ => (SomeException -> Bool) -> Async m a -> m ()+linkOnly shouldThrow a = do+ tid <- myThreadId+ void $ forkRepeat ("linkToOnly " <> show linkedThreadId) $ do+ r <- waitCatch a+ case r of+ Left e | shouldThrow e -> throwTo tid (exceptionInLinkedThread e)+ _otherwise -> return ()+ where+ linkedThreadId :: ThreadId m+ linkedThreadId = asyncThreadId a++ exceptionInLinkedThread :: SomeException -> ExceptionInLinkedThread+ exceptionInLinkedThread =+ ExceptionInLinkedThread (show linkedThreadId)++-- | Like 'Async.link2'.+link2 :: (MonadAsync m, MonadFork m, MonadMask m)+ => Async m a -> Async m b -> m ()+link2 = link2Only (not . isCancel)++-- | Like 'Async.link2Only'.+link2Only :: (MonadAsync m, MonadFork m, MonadMask m)+ => (SomeException -> Bool) -> Async m a -> Async m b -> m ()+link2Only shouldThrow left right =+ void $ forkRepeat ("link2Only " <> show (tl, tr)) $ do+ r <- waitEitherCatch left right+ case r of+ Left (Left e) | shouldThrow e ->+ throwTo tr (ExceptionInLinkedThread (show tl) e)+ Right (Left e) | shouldThrow e ->+ throwTo tl (ExceptionInLinkedThread (show tr) e)+ _ -> return ()+ where+ tl = asyncThreadId left+ tr = asyncThreadId right++isCancel :: SomeException -> Bool+isCancel e+ | Just AsyncCancelled <- fromException e = True+ | otherwise = False++forkRepeat :: (MonadFork m, MonadMask m) => String -> m a -> m (ThreadId m)+forkRepeat label action =+ mask $ \restore ->+ let go = do r <- tryAll (restore action)+ case r of+ Left _ -> go+ _ -> return ()+ in forkIO (labelThisThread label >> go)++tryAll :: MonadCatch m => m a -> m (Either SomeException a)+tryAll = try+++--+-- ReaderT instance+--++newtype AsyncReaderT r (m :: Type -> Type) a =+ AsyncReaderT { getAsyncReaderT :: Async m a }++instance ( MonadAsync m+ , MonadCatch (STM m)+ , MonadFork m+ , MonadMask m+ ) => MonadAsync (ReaderT r m) where+ type Async (ReaderT r m) = AsyncReaderT r m+ asyncThreadId (AsyncReaderT a) = asyncThreadId a++ async (ReaderT ma) = ReaderT $ \r -> AsyncReaderT <$> async (ma r)+ asyncBound (ReaderT ma) = ReaderT $ \r -> AsyncReaderT <$> asyncBound (ma r)+ asyncOn n (ReaderT ma) = ReaderT $ \r -> AsyncReaderT <$> asyncOn n (ma r)+ withAsync (ReaderT ma) f = ReaderT $ \r -> withAsync (ma r)+ $ \a -> runReaderT (f (AsyncReaderT a)) r+ withAsyncBound (ReaderT ma) f = ReaderT $ \r -> withAsyncBound (ma r)+ $ \a -> runReaderT (f (AsyncReaderT a)) r+ withAsyncOn n (ReaderT ma) f = ReaderT $ \r -> withAsyncOn n (ma r)+ $ \a -> runReaderT (f (AsyncReaderT a)) r++ asyncWithUnmask f = ReaderT $ \r -> fmap AsyncReaderT+ $ asyncWithUnmask+ $ \unmask -> runReaderT (f (liftF unmask)) r+ where+ liftF :: (m a -> m a) -> ReaderT r m a -> ReaderT r m a+ liftF g (ReaderT r) = ReaderT (g . r)++ asyncOnWithUnmask n f = ReaderT $ \r -> fmap AsyncReaderT+ $ asyncOnWithUnmask n+ $ \unmask -> runReaderT (f (liftF unmask)) r+ where+ liftF :: (m a -> m a) -> ReaderT r m a -> ReaderT r m a+ liftF g (ReaderT r) = ReaderT (g . r)++ withAsyncWithUnmask action f =+ ReaderT $ \r -> withAsyncWithUnmask (\unmask -> case action (liftF unmask) of+ ReaderT ma -> ma r)+ $ \a -> runReaderT (f (AsyncReaderT a)) r+ where+ liftF :: (m a -> m a) -> ReaderT r m a -> ReaderT r m a+ liftF g (ReaderT r) = ReaderT (g . r)++ withAsyncOnWithUnmask n action f =+ ReaderT $ \r -> withAsyncOnWithUnmask n (\unmask -> case action (liftF unmask) of+ ReaderT ma -> ma r)+ $ \a -> runReaderT (f (AsyncReaderT a)) r+ where+ liftF :: (m a -> m a) -> ReaderT r m a -> ReaderT r m a+ liftF g (ReaderT r) = ReaderT (g . r)++ waitCatchSTM = lift . waitCatchSTM . getAsyncReaderT+ pollSTM = lift . pollSTM . getAsyncReaderT++ race (ReaderT ma) (ReaderT mb) = ReaderT $ \r -> race (ma r) (mb r)+ race_ (ReaderT ma) (ReaderT mb) = ReaderT $ \r -> race_ (ma r) (mb r)+ concurrently (ReaderT ma) (ReaderT mb) = ReaderT $ \r -> concurrently (ma r) (mb r)++ wait = lift . wait . getAsyncReaderT+ poll = lift . poll . getAsyncReaderT+ waitCatch = lift . waitCatch . getAsyncReaderT+ cancel = lift . cancel . getAsyncReaderT+ uninterruptibleCancel = lift . uninterruptibleCancel+ . getAsyncReaderT+ cancelWith = (lift .: cancelWith)+ . getAsyncReaderT+ waitAny = fmap (first AsyncReaderT)+ . lift . waitAny+ . map getAsyncReaderT+ waitAnyCatch = fmap (first AsyncReaderT)+ . lift . waitAnyCatch+ . map getAsyncReaderT+ waitAnyCancel = fmap (first AsyncReaderT)+ . lift . waitAnyCancel+ . map getAsyncReaderT+ waitAnyCatchCancel = fmap (first AsyncReaderT)+ . lift . waitAnyCatchCancel+ . map getAsyncReaderT+ waitEither = on (lift .: waitEither) getAsyncReaderT+ waitEitherCatch = on (lift .: waitEitherCatch) getAsyncReaderT+ waitEitherCancel = on (lift .: waitEitherCancel) getAsyncReaderT+ waitEitherCatchCancel = on (lift .: waitEitherCatchCancel) getAsyncReaderT+ waitEither_ = on (lift .: waitEither_) getAsyncReaderT+ waitBoth = on (lift .: waitBoth) getAsyncReaderT+++--+-- Utilities+--++(.:) :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)+(f .: g) x y = f (g x y)+++-- | A higher order version of 'Data.Function.on'+--+on :: (f a -> f b -> c)+ -> (forall x. g x -> f x)+ -> (g a -> g b -> c)+on f g = \a b -> f (g a) (g b)
+ io-classes/Control/Monad/Class/MonadEventlog.hs view
@@ -0,0 +1,34 @@+module Control.Monad.Class.MonadEventlog (MonadEventlog (..)) where++import Control.Monad.Reader++import Debug.Trace qualified as IO (traceEventIO, traceMarkerIO)++class Monad m => MonadEventlog m where++ -- | Emits a message to the eventlog, if eventlog profiling is available and+ -- enabled at runtime.+ traceEventIO :: String -> m ()++ -- | Emits a marker to the eventlog, if eventlog profiling is available and+ -- enabled at runtime.+ --+ -- The 'String' is the name of the marker. The name is just used in the+ -- profiling tools to help you keep clear which marker is which.+ traceMarkerIO :: String -> m ()++--+-- Instances for IO+--++instance MonadEventlog IO where+ traceEventIO = IO.traceEventIO+ traceMarkerIO = IO.traceMarkerIO++--+-- Instance for ReaderT+--++instance MonadEventlog m => MonadEventlog (ReaderT r m) where+ traceEventIO = lift . traceEventIO+ traceMarkerIO = lift . traceMarkerIO
+ io-classes/Control/Monad/Class/MonadFork.hs view
@@ -0,0 +1,95 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE TypeFamilies #-}++-- | A generalisation of+-- <https://hackage.haskell.org/package/base/docs/Control-Concurrent.html Control.Concurrent>+-- API to both 'IO' and <https://hackage.haskell.org/package/io-sim IOSim>.+--+module Control.Monad.Class.MonadFork+ ( MonadThread (..)+ , labelThisThread+ , MonadFork (..)+ ) where++import Control.Concurrent qualified as IO+import Control.Exception (AsyncException (ThreadKilled), Exception,+ SomeException)+import Control.Monad.Reader (ReaderT (..), lift)+import Data.Kind (Type)+import GHC.Conc.Sync qualified as IO+++class (Monad m, Eq (ThreadId m),+ Ord (ThreadId m),+ Show (ThreadId m)) => MonadThread m where++ type ThreadId m :: Type++ myThreadId :: m (ThreadId m)+ labelThread :: ThreadId m -> String -> m ()++ -- | Requires ghc-9.6.1 or newer.+ --+ -- @since 1.8.0.0+ threadLabel :: ThreadId m -> m (Maybe String)++-- | Apply the label to the current thread+labelThisThread :: MonadThread m => String -> m ()+labelThisThread label = myThreadId >>= \tid -> labelThread tid label+++class MonadThread m => MonadFork m where++ forkIO :: m () -> m (ThreadId m)+ forkOn :: Int -> m () -> m (ThreadId m)+ forkIOWithUnmask :: ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)+ forkFinally :: m a -> (Either SomeException a -> m ()) -> m (ThreadId m)+ throwTo :: Exception e => ThreadId m -> e -> m ()++ killThread :: ThreadId m -> m ()+ killThread tid = throwTo tid ThreadKilled++ yield :: m ()++ getNumCapabilities :: m Int+++instance MonadThread IO where+ type ThreadId IO = IO.ThreadId+ myThreadId = IO.myThreadId+ labelThread = IO.labelThread+#if MIN_VERSION_base(4,18,0)+ threadLabel = IO.threadLabel+#else+ threadLabel = \_ -> pure Nothing+#endif++instance MonadFork IO where+ forkIO = IO.forkIO+ forkOn = IO.forkOn+ forkIOWithUnmask = IO.forkIOWithUnmask+ forkFinally = IO.forkFinally+ throwTo = IO.throwTo+ killThread = IO.killThread+ yield = IO.yield+ getNumCapabilities = IO.getNumCapabilities++instance MonadThread m => MonadThread (ReaderT r m) where+ type ThreadId (ReaderT r m) = ThreadId m+ myThreadId = lift myThreadId+ labelThread t l = lift (labelThread t l)+ threadLabel = lift . threadLabel++instance MonadFork m => MonadFork (ReaderT e m) where+ forkIO (ReaderT f) = ReaderT $ \e -> forkIO (f e)+ forkOn n (ReaderT f) = ReaderT $ \e -> forkOn n (f e)+ forkIOWithUnmask k = ReaderT $ \e -> forkIOWithUnmask $ \restore ->+ let restore' :: ReaderT e m a -> ReaderT e m a+ restore' (ReaderT f) = ReaderT $ restore . f+ in runReaderT (k restore') e+ forkFinally f k = ReaderT $ \e -> forkFinally (runReaderT f e)+ $ \err -> runReaderT (k err) e+ throwTo e t = lift (throwTo e t)+ yield = lift yield++ getNumCapabilities = lift getNumCapabilities
+ io-classes/Control/Monad/Class/MonadST.hs view
@@ -0,0 +1,57 @@+module Control.Monad.Class.MonadST (MonadST (..)) where++import Control.Monad.Reader++import Control.Monad.Primitive+import Control.Monad.ST (ST)+++-- | This class is for abstracting over 'stToIO' which allows running 'ST'+-- actions in 'IO'. In this case it is to allow running 'ST' actions within+-- another monad @m@.+--+-- The normal type of 'stToIO' is:+--+-- > stToIO :: ST RealWorld a -> IO a+--+-- We have two approaches to abstracting over this, a new and an older+-- (deprecated) method. The new method borrows the @primitive@ package's+-- 'PrimMonad' and 'PrimState' type family. This gives us:+--+-- > stToIO :: ST (PrimState m) a -> m a+--+-- Which for 'IO' is exactly the same as above. For 'ST' it is identity, while+-- for @IOSim@ it is+--+-- > stToIO :: ST s a -> IOSim s a+--+-- The older (deprecated) method is tricky because we need to not care about+-- both the @IO@, and also the @RealWorld@, and it does so avoiding mentioning+-- any @s@ type (which is what the 'PrimState' type family gives access to).+-- The solution is to write an action that is given the @liftST@ as an argument+-- and where that action itself is polymorphic in the @s@ parameter. This+-- allows us to instantiate it with @RealWorld@ in the @IO@ case, and the local+-- @s@ in a case where we are embedding into another @ST@ action.+--+class PrimMonad m => MonadST m where+ -- | @since 1.4.1.0+ stToIO :: ST (PrimState m) a -> m a++ -- | Deprecated. Use 'stToIO' instead.+ withLiftST :: (forall s. (forall a. ST s a -> m a) -> b) -> b+ withLiftST = \k -> k stToIO++{-# DEPRECATED withLiftST "Use the simpler 'stToIO' instead." #-}++instance MonadST IO where+ stToIO = stToPrim++instance MonadST (ST s) where+ stToIO = stToPrim+ withLiftST = \f -> f id++instance (MonadST m, PrimMonad m) => MonadST (ReaderT r m) where+ stToIO :: ST (PrimState m) a -> ReaderT r m a+ stToIO f = lift (stToPrim f)++ withLiftST f = withLiftST $ \g -> f (lift . g)
+ io-classes/Control/Monad/Class/MonadSTM.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+-- undecidable instances needed for 'WrappedSTM' instances of 'MonadThrow' and+-- 'MonadCatch' type classes.+{-# LANGUAGE UndecidableInstances #-}++-- | This module corresponds to "Control.Monad.STM" in "stm" package+--+module Control.Monad.Class.MonadSTM+ ( MonadSTM (STM, atomically, retry, orElse, check)+ , throwSTM+ -- * non standard extensions+ --+ -- $non-standard-extensions+ , MonadLabelledSTM+ , MonadTraceSTM (..)+ , TraceValue (..)+ , MonadInspectSTM (..)+ ) where++import Control.Monad.Class.MonadSTM.Internal++-- $non-standard-extensions+--+-- The non standard extensions include `MonadLabelledSTM` and `MonadTraceSTM` /+-- `MonadInspectSTM`. For `IO` these are all no-op, however they greatly+-- enhance [`IOSim`](https://hackage.haskell.org/package/io-sim) capabilities.+-- They are not only useful for debugging concurrency issues, but also to write+-- testable properties.
+ io-classes/Control/Monad/Class/MonadSTM/Internal.hs view
@@ -0,0 +1,1309 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeFamilyDependencies #-}++-- needed for `ReaderT` instance+{-# LANGUAGE UndecidableInstances #-}++-- Internal module. It's only exposed as it provides various default types for+-- defining new instances, otherwise prefer to use+-- 'Control.Concurrent.Class.MonadSTM'.+--+module Control.Monad.Class.MonadSTM.Internal+ ( MonadSTM (..)+ , MonadLabelledSTM (..)+ , MonadInspectSTM (..)+ , TraceValue (TraceValue, TraceDynamic, TraceString, DontTrace, traceDynamic, traceString)+ , MonadTraceSTM (..)+ -- * MonadThrow aliases+ , throwSTM+ , catchSTM+ -- * Default implementations+ -- $default-implementations+ --+ -- ** Default 'TMVar' implementation+ , TMVarDefault (..)+ , newTMVarDefault+ , newEmptyTMVarDefault+ , takeTMVarDefault+ , tryTakeTMVarDefault+ , putTMVarDefault+ , tryPutTMVarDefault+ , readTMVarDefault+ , tryReadTMVarDefault+ , swapTMVarDefault+ , writeTMVarDefault+ , isEmptyTMVarDefault+ , labelTMVarDefault+ , traceTMVarDefault+ -- ** Default 'TQueue' implementation+ , TQueueDefault (..)+ , newTQueueDefault+ , writeTQueueDefault+ , readTQueueDefault+ , tryReadTQueueDefault+ , isEmptyTQueueDefault+ , peekTQueueDefault+ , tryPeekTQueueDefault+ , flushTQueueDefault+ , unGetTQueueDefault+ , labelTQueueDefault+ -- ** Default 'TBQueue' implementation+ , TBQueueDefault (..)+ , newTBQueueDefault+ , writeTBQueueDefault+ , readTBQueueDefault+ , tryReadTBQueueDefault+ , peekTBQueueDefault+ , tryPeekTBQueueDefault+ , isEmptyTBQueueDefault+ , isFullTBQueueDefault+ , lengthTBQueueDefault+ , flushTBQueueDefault+ , unGetTBQueueDefault+ , labelTBQueueDefault+ -- ** Default 'TArray' implementation+ , TArrayDefault (..)+ -- ** Default 'TSem' implementation+ , TSemDefault (..)+ , newTSemDefault+ , waitTSemDefault+ , signalTSemDefault+ , signalTSemNDefault+ , labelTSemDefault+ -- ** Default 'TChan' implementation+ , TChanDefault (..)+ , newTChanDefault+ , newBroadcastTChanDefault+ , writeTChanDefault+ , readTChanDefault+ , tryReadTChanDefault+ , peekTChanDefault+ , tryPeekTChanDefault+ , dupTChanDefault+ , unGetTChanDefault+ , isEmptyTChanDefault+ , cloneTChanDefault+ , labelTChanDefault+ -- * Trace tvar and tmvar+ , debugTraceTVar+ , debugTraceTVarIO+ , debugTraceTMVar+ , debugTraceTMVarIO+ ) where++import Prelude hiding (read)++import Control.Concurrent.STM.TArray qualified as STM+import Control.Concurrent.STM.TBQueue qualified as STM+import Control.Concurrent.STM.TChan qualified as STM+import Control.Concurrent.STM.TMVar qualified as STM+import Control.Concurrent.STM.TQueue qualified as STM+import Control.Concurrent.STM.TSem qualified as STM+import Control.Concurrent.STM.TVar qualified as STM+import Control.Monad (unless, when)+import Control.Monad.STM qualified as STM++import Control.Monad.Reader (ReaderT (..))+import Control.Monad.Trans (lift)++import Control.Monad.Class.MonadThrow qualified as MonadThrow++import Control.Exception+import Data.Array (Array, bounds)+import Data.Array qualified as Array+import Data.Array.Base (IArray (numElements), MArray (..), arrEleBottom,+ listArray, unsafeAt)+import Data.Foldable (traverse_)+import Data.Ix (Ix, rangeSize)+import Data.Kind (Type)+import Data.Proxy (Proxy (..))+import Data.Typeable (Typeable)+import GHC.Stack+import Numeric.Natural (Natural)+++-- $default-implementations+--+-- The default implementations are based on a `TVar` defined in the class. They+-- are tailored towards `IOSim` rather than instances which would like to derive+-- from `IO` or monad transformers.+++-- | The STM primitives parametrised by a monad `m`.+--+class (Monad m, Monad (STM m)) => MonadSTM m where+ -- | The STM monad.+ type STM m = (stm :: Type -> Type) | stm -> m+ -- | Atomically run an STM computation.+ --+ -- See `STM.atomically`.+ atomically :: HasCallStack => STM m a -> m a++ -- | A type of a 'TVar'.+ --+ -- See `STM.TVar'.+ type TVar m :: Type -> Type++ newTVar :: a -> STM m (TVar m a)+ readTVar :: TVar m a -> STM m a+ writeTVar :: TVar m a -> a -> STM m ()+ -- | See `STM.retry`.+ retry :: STM m a+ -- | See `STM.orElse`.+ orElse :: STM m a -> STM m a -> STM m a++ modifyTVar :: TVar m a -> (a -> a) -> STM m ()+ modifyTVar v f = readTVar v >>= writeTVar v . f++ modifyTVar' :: TVar m a -> (a -> a) -> STM m ()+ modifyTVar' v f = readTVar v >>= \x -> writeTVar v $! f x++ -- | @since io-classes-0.2.0.0+ stateTVar :: TVar m s -> (s -> (a, s)) -> STM m a+ stateTVar = stateTVarDefault++ swapTVar :: TVar m a -> a -> STM m a+ swapTVar = swapTVarDefault++ -- | See `STM.check`.+ check :: Bool -> STM m ()+ check True = return ()+ check _ = retry++ -- Additional derived STM APIs+ type TMVar m :: Type -> Type+ newTMVar :: a -> STM m (TMVar m a)+ newEmptyTMVar :: STM m (TMVar m a)+ takeTMVar :: TMVar m a -> STM m a+ tryTakeTMVar :: TMVar m a -> STM m (Maybe a)+ putTMVar :: TMVar m a -> a -> STM m ()+ tryPutTMVar :: TMVar m a -> a -> STM m Bool+ readTMVar :: TMVar m a -> STM m a+ tryReadTMVar :: TMVar m a -> STM m (Maybe a)+ swapTMVar :: TMVar m a -> a -> STM m a+ writeTMVar :: TMVar m a -> a -> STM m ()+ isEmptyTMVar :: TMVar m a -> STM m Bool++ type TQueue m :: Type -> Type+ newTQueue :: STM m (TQueue m a)+ readTQueue :: TQueue m a -> STM m a+ tryReadTQueue :: TQueue m a -> STM m (Maybe a)+ peekTQueue :: TQueue m a -> STM m a+ tryPeekTQueue :: TQueue m a -> STM m (Maybe a)+ flushTQueue :: TQueue m a -> STM m [a]+ writeTQueue :: TQueue m a -> a -> STM m ()+ isEmptyTQueue :: TQueue m a -> STM m Bool+ unGetTQueue :: TQueue m a -> a -> STM m ()++ type TBQueue m :: Type -> Type+ newTBQueue :: Natural -> STM m (TBQueue m a)+ readTBQueue :: TBQueue m a -> STM m a+ tryReadTBQueue :: TBQueue m a -> STM m (Maybe a)+ peekTBQueue :: TBQueue m a -> STM m a+ tryPeekTBQueue :: TBQueue m a -> STM m (Maybe a)+ flushTBQueue :: TBQueue m a -> STM m [a]+ writeTBQueue :: TBQueue m a -> a -> STM m ()+ -- | @since 0.2.0.0+ lengthTBQueue :: TBQueue m a -> STM m Natural+ isEmptyTBQueue :: TBQueue m a -> STM m Bool+ isFullTBQueue :: TBQueue m a -> STM m Bool+ unGetTBQueue :: TBQueue m a -> a -> STM m ()++ type TArray m :: Type -> Type -> Type++ type TSem m :: Type+ newTSem :: Integer -> STM m (TSem m)+ waitTSem :: TSem m -> STM m ()+ signalTSem :: TSem m -> STM m ()+ signalTSemN :: Natural -> TSem m -> STM m ()++ type TChan m :: Type -> Type+ newTChan :: STM m (TChan m a)+ newBroadcastTChan :: STM m (TChan m a)+ dupTChan :: TChan m a -> STM m (TChan m a)+ cloneTChan :: TChan m a -> STM m (TChan m a)+ readTChan :: TChan m a -> STM m a+ tryReadTChan :: TChan m a -> STM m (Maybe a)+ peekTChan :: TChan m a -> STM m a+ tryPeekTChan :: TChan m a -> STM m (Maybe a)+ writeTChan :: TChan m a -> a -> STM m ()+ unGetTChan :: TChan m a -> a -> STM m ()+ isEmptyTChan :: TChan m a -> STM m Bool+++ -- Helpful derived functions with default implementations++ newTVarIO :: a -> m (TVar m a)+ readTVarIO :: TVar m a -> m a+ newTMVarIO :: a -> m (TMVar m a)+ newEmptyTMVarIO :: m (TMVar m a)+ newTQueueIO :: m (TQueue m a)+ newTBQueueIO :: Natural -> m (TBQueue m a)+ newTChanIO :: m (TChan m a)+ newBroadcastTChanIO :: m (TChan m a)++ --+ -- default implementations+ --++ newTVarIO = atomically . newTVar+ readTVarIO = atomically . readTVar+ newTMVarIO = atomically . newTMVar+ newEmptyTMVarIO = atomically newEmptyTMVar+ newTQueueIO = atomically newTQueue+ newTBQueueIO = atomically . newTBQueue+ newTChanIO = atomically newTChan+ newBroadcastTChanIO = atomically newBroadcastTChan++++stateTVarDefault :: MonadSTM m => TVar m s -> (s -> (a, s)) -> STM m a+stateTVarDefault var f = do+ s <- readTVar var+ let (a, s') = f s+ writeTVar var s'+ return a++swapTVarDefault :: MonadSTM m => TVar m a -> a -> STM m a+swapTVarDefault var new = do+ old <- readTVar var+ writeTVar var new+ return old+++-- | Labelled `TVar`s & friends.+--+-- The `IO` instances is no-op, the `IOSim` instance enhances simulation trace.+-- This is very useful when analysing low lever concurrency issues (e.g.+-- deadlocks, livelocks etc).+--+class MonadSTM m+ => MonadLabelledSTM m where+ -- | Name a `TVar`.+ labelTVar :: TVar m a -> String -> STM m ()+ labelTMVar :: TMVar m a -> String -> STM m ()+ labelTQueue :: TQueue m a -> String -> STM m ()+ labelTBQueue :: TBQueue m a -> String -> STM m ()+ labelTArray :: (Ix i, Show i)+ => TArray m i e -> String -> STM m ()+ labelTSem :: TSem m -> String -> STM m ()+ labelTChan :: TChan m a -> String -> STM m ()++ labelTVarIO :: TVar m a -> String -> m ()+ labelTMVarIO :: TMVar m a -> String -> m ()+ labelTQueueIO :: TQueue m a -> String -> m ()+ labelTBQueueIO :: TBQueue m a -> String -> m ()+ labelTArrayIO :: (Ix i, Show i)+ => TArray m i e -> String -> m ()+ labelTSemIO :: TSem m -> String -> m ()+ labelTChanIO :: TChan m a -> String -> m ()++ --+ -- default implementations+ --++ default labelTMVar :: TMVar m ~ TMVarDefault m+ => TMVar m a -> String -> STM m ()+ labelTMVar = labelTMVarDefault++ default labelTQueue :: TQueue m ~ TQueueDefault m+ => TQueue m a -> String -> STM m ()+ labelTQueue = labelTQueueDefault++ default labelTBQueue :: TBQueue m ~ TBQueueDefault m+ => TBQueue m a -> String -> STM m ()+ labelTBQueue = labelTBQueueDefault++ default labelTSem :: TSem m ~ TSemDefault m+ => TSem m -> String -> STM m ()+ labelTSem = labelTSemDefault++ default labelTChan :: TChan m ~ TChanDefault m+ => TChan m a -> String -> STM m ()+ labelTChan = labelTChanDefault++ default labelTArray :: ( TArray m ~ TArrayDefault m+ , Ix i+ , Show i+ )+ => TArray m i e -> String -> STM m ()+ labelTArray = labelTArrayDefault++ default labelTVarIO :: TVar m a -> String -> m ()+ labelTVarIO = \v l -> atomically (labelTVar v l)++ default labelTMVarIO :: TMVar m a -> String -> m ()+ labelTMVarIO = \v l -> atomically (labelTMVar v l)++ default labelTQueueIO :: TQueue m a -> String -> m ()+ labelTQueueIO = \v l -> atomically (labelTQueue v l)++ default labelTBQueueIO :: TBQueue m a -> String -> m ()+ labelTBQueueIO = \v l -> atomically (labelTBQueue v l)++ default labelTArrayIO :: (Ix i, Show i)+ => TArray m i e -> String -> m ()+ labelTArrayIO = \v l -> atomically (labelTArray v l)++ default labelTSemIO :: TSem m -> String -> m ()+ labelTSemIO = \v l -> atomically (labelTSem v l)++ default labelTChanIO :: TChan m a -> String -> m ()+ labelTChanIO = \v l -> atomically (labelTChan v l)+++-- | This type class is indented for+-- ['io-sim'](https://hackage.haskell.org/package/io-sim), where one might want+-- to access a 'TVar' in the underlying 'ST' monad.+--+class ( MonadSTM m+ , Monad (InspectMonadSTM m)+ )+ => MonadInspectSTM m where+ type InspectMonadSTM m :: Type -> Type+ -- | Return the value of a `TVar` as an `InspectMonad` computation.+ --+ -- `inspectTVar` is useful if the value of a `TVar` observed by `traceTVar`+ -- contains other `TVar`s.+ inspectTVar :: proxy m -> TVar m a -> InspectMonadSTM m a+ -- | Return the value of a `TMVar` as an `InspectMonad` computation.+ inspectTMVar :: proxy m -> TMVar m a -> InspectMonadSTM m (Maybe a)+ -- TODO: inspectTQueue, inspectTBQueue++instance MonadInspectSTM IO where+ type InspectMonadSTM IO = IO+ inspectTVar _ = readTVarIO+ -- issue #3198: tryReadTMVarIO+ inspectTMVar _ = atomically . tryReadTMVar+++-- | A GADT which instructs how to trace the value. The 'traceDynamic' will+-- use dynamic tracing, e.g. "Control.Monad.IOSim.traceM"; while 'traceString'+-- will be traced with 'EventSay'. The `IOSim`s dynamic tracing allows to+-- recover the value from the simulation trace (see+-- "Control.Monad.IOSim.selectTraceEventsDynamic").+--+data TraceValue where+ TraceValue :: forall tr. Typeable tr+ => { traceDynamic :: Maybe tr+ , traceString :: Maybe String+ }+ -> TraceValue+++-- | Use only a dynamic tracer.+--+pattern TraceDynamic :: () => forall tr. Typeable tr => tr -> TraceValue+pattern TraceDynamic tr <- TraceValue { traceDynamic = Just tr }+ where+ TraceDynamic tr = TraceValue { traceDynamic = Just tr, traceString = Nothing }++-- | Use only string tracing.+--+pattern TraceString :: String -> TraceValue+pattern TraceString tr <- TraceValue { traceString = Just tr }+ where+ TraceString tr = TraceValue { traceDynamic = (Nothing :: Maybe ())+ , traceString = Just tr+ }++-- | Do not trace the value.+--+pattern DontTrace :: TraceValue+pattern DontTrace <- TraceValue Nothing Nothing+ where+ DontTrace = TraceValue (Nothing :: Maybe ()) Nothing++-- | 'MonadTraceSTM' allows to trace values of stm variables when stm+-- transaction is committed. This allows to verify invariants when a variable+-- is committed.+--+class MonadInspectSTM m+ => MonadTraceSTM m where+ {-# MINIMAL traceTVar, traceTQueue, traceTBQueue #-}++ -- | Construct a trace output out of previous & new value of a 'TVar'. The+ -- callback is called whenever an stm transaction which modifies the 'TVar' is+ -- committed.+ --+ -- This is supported by 'IOSim' (and 'IOSimPOR'); 'IO' has a trivial instance.+ --+ -- The simplest example is:+ --+ -- >+ -- > traceTVar (Proxy @m) tvar (\_ -> TraceString . show)+ -- >+ --+ -- Note that the interpretation of `TraceValue` depends on the monad `m`+ -- itself (see 'TraceValue').+ --+ traceTVar :: proxy m+ -> TVar m a+ -> (Maybe a -> a -> InspectMonadSTM m TraceValue)+ -- ^ callback which receives initial value or 'Nothing' (if it+ -- is a newly created 'TVar'), and the committed value.+ -> STM m ()+++ traceTMVar :: proxy m+ -> TMVar m a+ -> (Maybe (Maybe a) -> (Maybe a) -> InspectMonadSTM m TraceValue)+ -> STM m ()++ traceTQueue :: proxy m+ -> TQueue m a+ -> (Maybe [a] -> [a] -> InspectMonadSTM m TraceValue)+ -> STM m ()++ traceTBQueue :: proxy m+ -> TBQueue m a+ -> (Maybe [a] -> [a] -> InspectMonadSTM m TraceValue)+ -> STM m ()++ traceTSem :: proxy m+ -> TSem m+ -> (Maybe Integer -> Integer -> InspectMonadSTM m TraceValue)+ -> STM m ()++ default traceTMVar :: TMVar m a ~ TMVarDefault m a+ => proxy m+ -> TMVar m a+ -> (Maybe (Maybe a) -> Maybe a -> InspectMonadSTM m TraceValue)+ -> STM m ()+ traceTMVar = traceTMVarDefault++ default traceTSem :: TSem m ~ TSemDefault m+ => proxy m+ -> TSem m+ -> (Maybe Integer -> Integer -> InspectMonadSTM m TraceValue)+ -> STM m ()+ traceTSem = traceTSemDefault+++ traceTVarIO :: TVar m a+ -> (Maybe a -> a -> InspectMonadSTM m TraceValue)+ -> m ()++ traceTMVarIO :: TMVar m a+ -> (Maybe (Maybe a) -> Maybe a -> InspectMonadSTM m TraceValue)+ -> m ()++ traceTQueueIO :: TQueue m a+ -> (Maybe [a] -> [a] -> InspectMonadSTM m TraceValue)+ -> m ()++ traceTBQueueIO :: TBQueue m a+ -> (Maybe [a] -> [a] -> InspectMonadSTM m TraceValue)+ -> m ()++ traceTSemIO :: TSem m+ -> (Maybe Integer -> Integer -> InspectMonadSTM m TraceValue)+ -> m ()++ default traceTVarIO :: TVar m a+ -> (Maybe a -> a -> InspectMonadSTM m TraceValue)+ -> m ()+ traceTVarIO = \v f -> atomically (traceTVar Proxy v f)++ default traceTMVarIO :: TMVar m a+ -> (Maybe (Maybe a) -> (Maybe a) -> InspectMonadSTM m TraceValue)+ -> m ()+ traceTMVarIO = \v f -> atomically (traceTMVar Proxy v f)++ default traceTQueueIO :: TQueue m a+ -> (Maybe [a] -> [a] -> InspectMonadSTM m TraceValue)+ -> m ()+ traceTQueueIO = \v f -> atomically (traceTQueue Proxy v f)++ default traceTBQueueIO :: TBQueue m a+ -> (Maybe [a] -> [a] -> InspectMonadSTM m TraceValue)+ -> m ()+ traceTBQueueIO = \v f -> atomically (traceTBQueue Proxy v f)++ default traceTSemIO :: TSem m+ -> (Maybe Integer -> Integer -> InspectMonadSTM m TraceValue)+ -> m ()+ traceTSemIO = \v f -> atomically (traceTSem Proxy v f)++debugTraceTVar :: (MonadTraceSTM m, Show a)+ => proxy m+ -> TVar m a+ -> STM m ()+debugTraceTVar p tvar =+ traceTVar p tvar (\pv v -> pure $ TraceString $ case (pv, v) of+ (Nothing, _) -> error "Unreachable"+ (Just st', st'') -> "Modified: " <> show st' <> " -> " <> show st''+ )++debugTraceTVarIO :: (MonadTraceSTM m, Show a)+ => TVar m a+ -> m ()+debugTraceTVarIO tvar =+ traceTVarIO tvar (\pv v -> pure $ TraceString $ case (pv, v) of+ (Nothing, _) -> error "Unreachable"+ (Just st', st'') -> "Modified: " <> show st' <> " -> " <> show st''+ )++debugTraceTMVar :: (MonadTraceSTM m, Show a)+ => proxy m+ -> TMVar m a+ -> STM m ()+debugTraceTMVar p tmvar =+ traceTMVar p tmvar (\pv v -> pure $ TraceString $ case (pv, v) of+ (Nothing, _) -> error "Unreachable"+ (Just Nothing, Just st') -> "Put: " <> show st'+ (Just Nothing, Nothing) -> "Remains empty"+ (Just Just{}, Nothing) -> "Take"+ (Just (Just st'), Just st'') -> "Modified: " <> show st' <> " -> " <> show st''+ )++debugTraceTMVarIO :: (Show a, MonadTraceSTM m)+ => TMVar m a+ -> m ()+debugTraceTMVarIO tmvar =+ traceTMVarIO tmvar (\pv v -> pure $ TraceString $ case (pv, v) of+ (Nothing, _) -> error "Unreachable"+ (Just Nothing, Just st') -> "Put: " <> show st'+ (Just Nothing, Nothing) -> "Remains empty"+ (Just Just{}, Nothing) -> "Take"+ (Just (Just st'), Just st'') -> "Modified: " <> show st' <> " -> " <> show st''+ )++--+-- Instance for IO uses the existing STM library implementations+--++instance MonadSTM IO where+ type STM IO = STM.STM++ atomically = wrapBlockedIndefinitely . STM.atomically++ type TVar IO = STM.TVar+ type TMVar IO = STM.TMVar+ type TQueue IO = STM.TQueue+ type TBQueue IO = STM.TBQueue+ type TArray IO = STM.TArray+ type TSem IO = STM.TSem+ type TChan IO = STM.TChan++ newTVar = STM.newTVar+ readTVar = STM.readTVar+ writeTVar = STM.writeTVar+ retry = STM.retry+ orElse = STM.orElse+ modifyTVar = STM.modifyTVar+ modifyTVar' = STM.modifyTVar'+ stateTVar = STM.stateTVar+ swapTVar = STM.swapTVar+ check = STM.check+ newTMVar = STM.newTMVar+ newEmptyTMVar = STM.newEmptyTMVar+ takeTMVar = STM.takeTMVar+ tryTakeTMVar = STM.tryTakeTMVar+ putTMVar = STM.putTMVar+ tryPutTMVar = STM.tryPutTMVar+ readTMVar = STM.readTMVar+ tryReadTMVar = STM.tryReadTMVar+ swapTMVar = STM.swapTMVar+#if MIN_VERSION_stm(2, 5, 1)+ writeTMVar = STM.writeTMVar+#else+ writeTMVar = writeTMVar'+#endif+ isEmptyTMVar = STM.isEmptyTMVar+ newTQueue = STM.newTQueue+ readTQueue = STM.readTQueue+ tryReadTQueue = STM.tryReadTQueue+ peekTQueue = STM.peekTQueue+ tryPeekTQueue = STM.tryPeekTQueue+ flushTQueue = STM.flushTQueue+ writeTQueue = STM.writeTQueue+ isEmptyTQueue = STM.isEmptyTQueue+ unGetTQueue = STM.unGetTQueue+ newTBQueue = STM.newTBQueue+ readTBQueue = STM.readTBQueue+ tryReadTBQueue = STM.tryReadTBQueue+ peekTBQueue = STM.peekTBQueue+ tryPeekTBQueue = STM.tryPeekTBQueue+ writeTBQueue = STM.writeTBQueue+ flushTBQueue = STM.flushTBQueue+ lengthTBQueue = STM.lengthTBQueue+ isEmptyTBQueue = STM.isEmptyTBQueue+ isFullTBQueue = STM.isFullTBQueue+ unGetTBQueue = STM.unGetTBQueue+ newTSem = STM.newTSem+ waitTSem = STM.waitTSem+ signalTSem = STM.signalTSem+ signalTSemN = STM.signalTSemN++ newTChan = STM.newTChan+ newBroadcastTChan = STM.newBroadcastTChan+ dupTChan = STM.dupTChan+ cloneTChan = STM.cloneTChan+ readTChan = STM.readTChan+ tryReadTChan = STM.tryReadTChan+ peekTChan = STM.peekTChan+ tryPeekTChan = STM.tryPeekTChan+ writeTChan = STM.writeTChan+ unGetTChan = STM.unGetTChan+ isEmptyTChan = STM.isEmptyTChan++ newTVarIO = STM.newTVarIO+ readTVarIO = STM.readTVarIO+ newTMVarIO = STM.newTMVarIO+ newEmptyTMVarIO = STM.newEmptyTMVarIO+ newTQueueIO = STM.newTQueueIO+ newTBQueueIO = STM.newTBQueueIO+ newTChanIO = STM.newTChanIO+ newBroadcastTChanIO = STM.newBroadcastTChanIO++-- | noop instance+--+instance MonadLabelledSTM IO where+ labelTVar = \_ _ -> return ()+ labelTMVar = \_ _ -> return ()+ labelTQueue = \_ _ -> return ()+ labelTBQueue = \_ _ -> return ()+ labelTArray = \_ _ -> return ()+ labelTSem = \_ _ -> return ()+ labelTChan = \_ _ -> return ()++ labelTVarIO = \_ _ -> return ()+ labelTMVarIO = \_ _ -> return ()+ labelTQueueIO = \_ _ -> return ()+ labelTBQueueIO = \_ _ -> return ()+ labelTArrayIO = \_ _ -> return ()+ labelTSemIO = \_ _ -> return ()+ labelTChanIO = \_ _ -> return ()++-- | noop instance+--+instance MonadTraceSTM IO where+ traceTVar = \_ _ _ -> return ()+ traceTMVar = \_ _ _ -> return ()+ traceTQueue = \_ _ _ -> return ()+ traceTBQueue = \_ _ _ -> return ()+ traceTSem = \_ _ _ -> return ()++ traceTVarIO = \_ _ -> return ()+ traceTMVarIO = \_ _ -> return ()+ traceTQueueIO = \_ _ -> return ()+ traceTBQueueIO = \_ _ -> return ()+ traceTSemIO = \_ _ -> return ()++-- | Wrapper around 'BlockedIndefinitelyOnSTM' that stores a call stack+data BlockedIndefinitely = BlockedIndefinitely {+ blockedIndefinitelyCallStack :: CallStack+ , blockedIndefinitelyException :: BlockedIndefinitelyOnSTM+ }+ deriving Show++instance Exception BlockedIndefinitely where+ displayException (BlockedIndefinitely cs e) = unlines [+ displayException e+ , prettyCallStack cs+ ]++wrapBlockedIndefinitely :: HasCallStack => IO a -> IO a+wrapBlockedIndefinitely = handle (throwIO . BlockedIndefinitely callStack)++--+-- Default TMVar implementation in terms of TVars+--++newtype TMVarDefault m a = TMVar (TVar m (Maybe a))++labelTMVarDefault+ :: MonadLabelledSTM m+ => TMVarDefault m a -> String -> STM m ()+labelTMVarDefault (TMVar tvar) = labelTVar tvar++traceTMVarDefault+ :: MonadTraceSTM m+ => proxy m+ -> TMVarDefault m a+ -> (Maybe (Maybe a) -> Maybe a -> InspectMonadSTM m TraceValue)+ -> STM m ()+traceTMVarDefault p (TMVar t) f = traceTVar p t f++newTMVarDefault :: MonadSTM m => a -> STM m (TMVarDefault m a)+newTMVarDefault a = do+ t <- newTVar (Just a)+ return (TMVar t)++newEmptyTMVarDefault :: MonadSTM m => STM m (TMVarDefault m a)+newEmptyTMVarDefault = do+ t <- newTVar Nothing+ return (TMVar t)++takeTMVarDefault :: MonadSTM m => TMVarDefault m a -> STM m a+takeTMVarDefault (TMVar t) = do+ m <- readTVar t+ case m of+ Nothing -> retry+ Just a -> do writeTVar t Nothing; return a++tryTakeTMVarDefault :: MonadSTM m => TMVarDefault m a -> STM m (Maybe a)+tryTakeTMVarDefault (TMVar t) = do+ m <- readTVar t+ case m of+ Nothing -> return Nothing+ Just a -> do writeTVar t Nothing; return (Just a)++putTMVarDefault :: MonadSTM m => TMVarDefault m a -> a -> STM m ()+putTMVarDefault (TMVar t) a = do+ m <- readTVar t+ case m of+ Nothing -> do writeTVar t (Just a); return ()+ Just _ -> retry++tryPutTMVarDefault :: MonadSTM m => TMVarDefault m a -> a -> STM m Bool+tryPutTMVarDefault (TMVar t) a = do+ m <- readTVar t+ case m of+ Nothing -> do writeTVar t (Just a); return True+ Just _ -> return False++readTMVarDefault :: MonadSTM m => TMVarDefault m a -> STM m a+readTMVarDefault (TMVar t) = do+ m <- readTVar t+ case m of+ Nothing -> retry+ Just a -> return a++tryReadTMVarDefault :: MonadSTM m => TMVarDefault m a -> STM m (Maybe a)+tryReadTMVarDefault (TMVar t) = readTVar t++swapTMVarDefault :: MonadSTM m => TMVarDefault m a -> a -> STM m a+swapTMVarDefault (TMVar t) new = do+ m <- readTVar t+ case m of+ Nothing -> retry+ Just old -> do writeTVar t (Just new); return old++writeTMVarDefault :: MonadSTM m => TMVarDefault m a -> a -> STM m ()+writeTMVarDefault (TMVar t) new = writeTVar t (Just new)++isEmptyTMVarDefault :: MonadSTM m => TMVarDefault m a -> STM m Bool+isEmptyTMVarDefault (TMVar t) = do+ m <- readTVar t+ case m of+ Nothing -> return True+ Just _ -> return False++--+-- Default TQueue implementation in terms of TVars (used by sim)+--++data TQueueDefault m a = TQueue !(TVar m [a])+ !(TVar m [a])++labelTQueueDefault+ :: MonadLabelledSTM m+ => TQueueDefault m a -> String -> STM m ()+labelTQueueDefault (TQueue read write) label = do+ labelTVar read (label ++ "-read")+ labelTVar write (label ++ "-write")++newTQueueDefault :: MonadSTM m => STM m (TQueueDefault m a)+newTQueueDefault = do+ read <- newTVar []+ write <- newTVar []+ return (TQueue read write)++writeTQueueDefault :: MonadSTM m => TQueueDefault m a -> a -> STM m ()+writeTQueueDefault (TQueue _read write) a = do+ listend <- readTVar write+ writeTVar write (a:listend)++readTQueueDefault :: MonadSTM m => TQueueDefault m a -> STM m a+readTQueueDefault queue = maybe retry return =<< tryReadTQueueDefault queue++tryReadTQueueDefault :: MonadSTM m => TQueueDefault m a -> STM m (Maybe a)+tryReadTQueueDefault (TQueue read write) = do+ xs <- readTVar read+ case xs of+ (x:xs') -> do+ writeTVar read xs'+ return (Just x)+ [] -> do+ ys <- readTVar write+ case reverse ys of+ [] -> return Nothing+ (z:zs) -> do+ writeTVar write []+ writeTVar read zs+ return (Just z)++isEmptyTQueueDefault :: MonadSTM m => TQueueDefault m a -> STM m Bool+isEmptyTQueueDefault (TQueue read write) = do+ xs <- readTVar read+ case xs of+ (_:_) -> return False+ [] -> do ys <- readTVar write+ case ys of+ [] -> return True+ _ -> return False++peekTQueueDefault :: MonadSTM m => TQueueDefault m a -> STM m a+peekTQueueDefault (TQueue read _write) = do+ xs <- readTVar read+ case xs of+ (x:_) -> return x+ _ -> retry++tryPeekTQueueDefault :: MonadSTM m => TQueueDefault m a -> STM m (Maybe a)+tryPeekTQueueDefault (TQueue read _write) = do+ xs <- readTVar read+ case xs of+ (x:_) -> return (Just x)+ _ -> return Nothing+++flushTQueueDefault :: MonadSTM m => TQueueDefault m a -> STM m [a]+flushTQueueDefault (TQueue read write) = do+ xs <- readTVar read+ ys <- readTVar write+ unless (null xs) $ writeTVar read []+ unless (null ys) $ writeTVar write []+ return (xs ++ reverse ys)++unGetTQueueDefault :: MonadSTM m => TQueueDefault m a -> a -> STM m ()+unGetTQueueDefault (TQueue read _write) a = modifyTVar read (a:)++++--+-- Default TBQueue implementation in terms of TVars+--++data TBQueueDefault m a = TBQueue+ !(TVar m Natural) -- read capacity+ !(TVar m [a]) -- elements waiting for read+ !(TVar m Natural) -- write capacity+ !(TVar m [a]) -- written elements+ !Natural++labelTBQueueDefault+ :: MonadLabelledSTM m+ => TBQueueDefault m a -> String -> STM m ()+labelTBQueueDefault (TBQueue rsize read wsize write _size) label = do+ labelTVar rsize (label ++ "-rsize")+ labelTVar read (label ++ "-read")+ labelTVar wsize (label ++ "-wsize")+ labelTVar write (label ++ "-write")++newTBQueueDefault :: MonadSTM m => Natural -> STM m (TBQueueDefault m a)+newTBQueueDefault size = do+ rsize <- newTVar 0+ read <- newTVar []+ wsize <- newTVar size+ write <- newTVar []+ return (TBQueue rsize read wsize write size)++readTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m a+readTBQueueDefault queue = maybe retry return =<< tryReadTBQueueDefault queue++tryReadTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m (Maybe a)+tryReadTBQueueDefault (TBQueue rsize read _wsize write _size) = do+ xs <- readTVar read+ r <- readTVar rsize+ writeTVar rsize $! r + 1+ case xs of+ (x:xs') -> do+ writeTVar read xs'+ return (Just x)+ [] -> do+ ys <- readTVar write+ case ys of+ [] -> return Nothing+ _ -> do+ -- NB. lazy: we want the transaction to be+ -- short, otherwise it will conflict+ let ~(z,zs) = case reverse ys of+ z':zs' -> (z',zs')+ _ -> error "tryReadTBQueueDefault: impossible"++ writeTVar write []+ writeTVar read zs+ return (Just z)++peekTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m a+peekTBQueueDefault (TBQueue _rsize read _wsize _write _size) = do+ xs <- readTVar read+ case xs of+ (x:_) -> return x+ _ -> retry++tryPeekTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m (Maybe a)+tryPeekTBQueueDefault (TBQueue _rsize read _wsize _write _size) = do+ xs <- readTVar read+ case xs of+ (x:_) -> return (Just x)+ _ -> return Nothing++writeTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> a -> STM m ()+writeTBQueueDefault (TBQueue rsize _read wsize write _size) a = do+ w <- readTVar wsize+ if (w > 0)+ then do writeTVar wsize $! w - 1+ else do+ r <- readTVar rsize+ if (r > 0)+ then do writeTVar rsize 0+ writeTVar wsize $! r - 1+ else retry+ listend <- readTVar write+ writeTVar write (a:listend)++isEmptyTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m Bool+isEmptyTBQueueDefault (TBQueue _rsize read _wsize write _size) = do+ xs <- readTVar read+ case xs of+ (_:_) -> return False+ [] -> do ys <- readTVar write+ case ys of+ [] -> return True+ _ -> return False++isFullTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m Bool+isFullTBQueueDefault (TBQueue rsize _read wsize _write _size) = do+ w <- readTVar wsize+ if (w > 0)+ then return False+ else do+ r <- readTVar rsize+ if (r > 0)+ then return False+ else return True++lengthTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m Natural+lengthTBQueueDefault (TBQueue rsize _read wsize _write size) = do+ r <- readTVar rsize+ w <- readTVar wsize+ return $! size - r - w+++flushTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m [a]+flushTBQueueDefault (TBQueue rsize read wsize write size) = do+ xs <- readTVar read+ ys <- readTVar write+ if null xs && null ys+ then return []+ else do+ writeTVar read []+ writeTVar write []+ writeTVar rsize 0+ writeTVar wsize size+ return (xs ++ reverse ys)++unGetTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> a -> STM m ()+unGetTBQueueDefault (TBQueue rsize read wsize _write _size) a = do+ r <- readTVar rsize+ if (r > 0)+ then do writeTVar rsize $! r - 1+ else do+ w <- readTVar wsize+ if (w > 0)+ then writeTVar wsize $! w - 1+ else retry+ xs <- readTVar read+ writeTVar read (a:xs)+++--+-- Default `TArray` implementation+--++-- | Default implementation of 'TArray'.+--+data TArrayDefault m i e = TArray (Array i (TVar m e))++deriving instance (Eq (TVar m e), Ix i) => Eq (TArrayDefault m i e)++instance (Monad stm, MonadSTM m, stm ~ STM m)+ => MArray (TArrayDefault m) e stm where+ getBounds (TArray a) = return (bounds a)+ newArray b e = do+ a <- rep (rangeSize b) (newTVar e)+ return $ TArray (listArray b a)+ newArray_ b = do+ a <- rep (rangeSize b) (newTVar arrEleBottom)+ return $ TArray (listArray b a)+ unsafeRead (TArray a) i = readTVar $ unsafeAt a i+ unsafeWrite (TArray a) i e = writeTVar (unsafeAt a i) e+ getNumElements (TArray a) = return (numElements a)++rep :: Monad m => Int -> m a -> m [a]+rep n m = go n []+ where+ go 0 xs = return xs+ go i xs = do+ x <- m+ go (i-1) (x:xs)++labelTArrayDefault :: ( MonadLabelledSTM m+ , Ix i+ , Show i+ )+ => TArrayDefault m i e -> String -> STM m ()+labelTArrayDefault (TArray arr) name = do+ let as = Array.assocs arr+ traverse_ (\(i, v) -> labelTVar v (name ++ ":" ++ show i)) as+++--+-- Default `TSem` implementation+--++newtype TSemDefault m = TSem (TVar m Integer)++labelTSemDefault :: MonadLabelledSTM m => TSemDefault m -> String -> STM m ()+labelTSemDefault (TSem t) = labelTVar t++traceTSemDefault :: MonadTraceSTM m+ => proxy m+ -> TSemDefault m+ -> (Maybe Integer -> Integer -> InspectMonadSTM m TraceValue)+ -> STM m ()+traceTSemDefault proxy (TSem t) k = traceTVar proxy t k++newTSemDefault :: MonadSTM m => Integer -> STM m (TSemDefault m)+newTSemDefault i = TSem <$> (newTVar $! i)++waitTSemDefault :: MonadSTM m => TSemDefault m -> STM m ()+waitTSemDefault (TSem t) = do+ i <- readTVar t+ when (i <= 0) retry+ writeTVar t $! (i-1)++signalTSemDefault :: MonadSTM m => TSemDefault m -> STM m ()+signalTSemDefault (TSem t) = do+ i <- readTVar t+ writeTVar t $! i+1++signalTSemNDefault :: MonadSTM m => Natural -> TSemDefault m -> STM m ()+signalTSemNDefault 0 _ = return ()+signalTSemNDefault 1 s = signalTSemDefault s+signalTSemNDefault n (TSem t) = do+ i <- readTVar t+ writeTVar t $! i+(toInteger n)++--+-- Default `TChan` implementation+--++type TVarList m a = TVar m (TList m a)+data TList m a = TNil | TCons a (TVarList m a)++data TChanDefault m a = TChan (TVar m (TVarList m a)) (TVar m (TVarList m a))++labelTChanDefault :: MonadLabelledSTM m => TChanDefault m a -> String -> STM m ()+labelTChanDefault (TChan read write) name = do+ labelTVar read (name ++ ":read")+ labelTVar write (name ++ ":write")++newTChanDefault :: MonadSTM m => STM m (TChanDefault m a)+newTChanDefault = do+ hole <- newTVar TNil+ read <- newTVar hole+ write <- newTVar hole+ return (TChan read write)++newBroadcastTChanDefault :: MonadSTM m => STM m (TChanDefault m a)+newBroadcastTChanDefault = do+ write_hole <- newTVar TNil+ read <- newTVar (error "reading from a TChan created by newBroadcastTChan; use dupTChan first")+ write <- newTVar write_hole+ return (TChan read write)++writeTChanDefault :: MonadSTM m => TChanDefault m a -> a -> STM m ()+writeTChanDefault (TChan _read write) a = do+ listend <- readTVar write -- listend == TVar pointing to TNil+ new_listend <- newTVar TNil+ writeTVar listend (TCons a new_listend)+ writeTVar write new_listend++readTChanDefault :: MonadSTM m => TChanDefault m a -> STM m a+readTChanDefault (TChan read _write) = do+ listhead <- readTVar read+ head_ <- readTVar listhead+ case head_ of+ TNil -> retry+ TCons a tail_ -> do+ writeTVar read tail_+ return a++tryReadTChanDefault :: MonadSTM m => TChanDefault m a -> STM m (Maybe a)+tryReadTChanDefault (TChan read _write) = do+ listhead <- readTVar read+ head_ <- readTVar listhead+ case head_ of+ TNil -> return Nothing+ TCons a tl -> do+ writeTVar read tl+ return (Just a)++peekTChanDefault :: MonadSTM m => TChanDefault m a -> STM m a+peekTChanDefault (TChan read _write) = do+ listhead <- readTVar read+ head_ <- readTVar listhead+ case head_ of+ TNil -> retry+ TCons a _ -> return a++tryPeekTChanDefault :: MonadSTM m => TChanDefault m a -> STM m (Maybe a)+tryPeekTChanDefault (TChan read _write) = do+ listhead <- readTVar read+ head_ <- readTVar listhead+ case head_ of+ TNil -> return Nothing+ TCons a _ -> return (Just a)++dupTChanDefault :: MonadSTM m => TChanDefault m a -> STM m (TChanDefault m a)+dupTChanDefault (TChan _read write) = do+ hole <- readTVar write+ new_read <- newTVar hole+ return (TChan new_read write)++unGetTChanDefault :: MonadSTM m => TChanDefault m a -> a -> STM m ()+unGetTChanDefault (TChan read _write) a = do+ listhead <- readTVar read+ newhead <- newTVar (TCons a listhead)+ writeTVar read newhead++isEmptyTChanDefault :: MonadSTM m => TChanDefault m a -> STM m Bool+isEmptyTChanDefault (TChan read _write) = do+ listhead <- readTVar read+ head_ <- readTVar listhead+ case head_ of+ TNil -> return True+ TCons _ _ -> return False++cloneTChanDefault :: MonadSTM m => TChanDefault m a -> STM m (TChanDefault m a)+cloneTChanDefault (TChan read write) = do+ readpos <- readTVar read+ new_read <- newTVar readpos+ return (TChan new_read write)+++-- | 'throwIO' specialised to @stm@ monad.+--+throwSTM :: (MonadSTM m, MonadThrow.MonadThrow (STM m), Exception e)+ => e -> STM m a+throwSTM = MonadThrow.throwIO+++-- | 'catch' specialized for an @stm@ monad.+--+catchSTM :: (MonadSTM m, MonadThrow.MonadCatch (STM m), Exception e)+ => STM m a -> (e -> STM m a) -> STM m a+catchSTM = MonadThrow.catch++--+-- ReaderT instance+--+++-- | The underlying stm monad is also transformed.+--+instance MonadSTM m => MonadSTM (ReaderT r m) where+ type STM (ReaderT r m) = ReaderT r (STM m)+ atomically (ReaderT stm) = ReaderT $ \r -> atomically (stm r)++ type TVar (ReaderT r m) = TVar m+ newTVar = lift . newTVar+ readTVar = lift . readTVar+ writeTVar = lift .: writeTVar+ retry = lift retry+ orElse (ReaderT a) (ReaderT b) = ReaderT $ \r -> a r `orElse` b r++ modifyTVar = lift .: modifyTVar+ modifyTVar' = lift .: modifyTVar'+ stateTVar = lift .: stateTVar+ swapTVar = lift .: swapTVar+ check = lift . check++ type TMVar (ReaderT r m) = TMVar m+ newTMVar = lift . newTMVar+ newEmptyTMVar = lift newEmptyTMVar+ takeTMVar = lift . takeTMVar+ tryTakeTMVar = lift . tryTakeTMVar+ putTMVar = lift .: putTMVar+ tryPutTMVar = lift .: tryPutTMVar+ readTMVar = lift . readTMVar+ tryReadTMVar = lift . tryReadTMVar+ swapTMVar = lift .: swapTMVar+ writeTMVar = lift .: writeTMVar+ isEmptyTMVar = lift . isEmptyTMVar++ type TQueue (ReaderT r m) = TQueue m+ newTQueue = lift newTQueue+ readTQueue = lift . readTQueue+ tryReadTQueue = lift . tryReadTQueue+ peekTQueue = lift . peekTQueue+ tryPeekTQueue = lift . tryPeekTQueue+ flushTQueue = lift . flushTQueue+ writeTQueue v = lift . writeTQueue v+ isEmptyTQueue = lift . isEmptyTQueue+ unGetTQueue = lift .: unGetTQueue++ type TBQueue (ReaderT r m) = TBQueue m+ newTBQueue = lift . newTBQueue+ readTBQueue = lift . readTBQueue+ tryReadTBQueue = lift . tryReadTBQueue+ peekTBQueue = lift . peekTBQueue+ tryPeekTBQueue = lift . tryPeekTBQueue+ flushTBQueue = lift . flushTBQueue+ writeTBQueue = lift .: writeTBQueue+ lengthTBQueue = lift . lengthTBQueue+ isEmptyTBQueue = lift . isEmptyTBQueue+ isFullTBQueue = lift . isFullTBQueue+ unGetTBQueue = lift .: unGetTBQueue++ type TArray (ReaderT r m) = TArray m++ type TSem (ReaderT r m) = TSem m+ newTSem = lift . newTSem+ waitTSem = lift . waitTSem+ signalTSem = lift . signalTSem+ signalTSemN = lift .: signalTSemN++ type TChan (ReaderT r m) = TChan m+ newTChan = lift newTChan+ newBroadcastTChan = lift newBroadcastTChan+ dupTChan = lift . dupTChan+ cloneTChan = lift . cloneTChan+ readTChan = lift . readTChan+ tryReadTChan = lift . tryReadTChan+ peekTChan = lift . peekTChan+ tryPeekTChan = lift . tryPeekTChan+ writeTChan = lift .: writeTChan+ unGetTChan = lift .: unGetTChan+ isEmptyTChan = lift . isEmptyTChan++instance MonadInspectSTM m => MonadInspectSTM (ReaderT r m) where+ type InspectMonadSTM (ReaderT r m) = InspectMonadSTM m+ inspectTVar _ = inspectTVar (Proxy :: Proxy m)+ inspectTMVar _ = inspectTMVar (Proxy :: Proxy m)++instance MonadTraceSTM m => MonadTraceSTM (ReaderT r m) where+ traceTVar _ = lift .: traceTVar Proxy+ traceTMVar _ = lift .: traceTMVar Proxy+ traceTQueue _ = lift .: traceTQueue Proxy+ traceTBQueue _ = lift .: traceTBQueue Proxy+ traceTSem _ = lift .: traceTSem Proxy++(.:) :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)+(f .: g) x y = f (g x y)++-- TODO: writeTMVar was introduced in stm-2.5.1. But io-sim supports stm older than that+-- Therefore this can be removed once we don't need backwards compatibility with stm.+#if !MIN_VERSION_stm(2,5,1)+writeTMVar' :: STM.TMVar a -> a -> STM.STM ()+writeTMVar' t new = STM.tryTakeTMVar t >> STM.putTMVar t new+#endif
+ io-classes/Control/Monad/Class/MonadSay.hs view
@@ -0,0 +1,13 @@+module Control.Monad.Class.MonadSay where++import Control.Monad.Reader+import Data.ByteString.Char8 qualified as BSC++class Monad m => MonadSay m where+ say :: String -> m ()++instance MonadSay IO where+ say = BSC.putStrLn . BSC.pack++instance MonadSay m => MonadSay (ReaderT r m) where+ say = lift . say
+ io-classes/Control/Monad/Class/MonadTest.hs view
@@ -0,0 +1,17 @@+module Control.Monad.Class.MonadTest (MonadTest (..)) where++import Control.Monad.Reader++-- | A helper monad for /IOSimPOR/.+class Monad m => MonadTest m where+ -- | Mark a thread for schedule exploration. All threads that are forked by+ -- it are also included in the exploration.+ --+ exploreRaces :: m ()+ exploreRaces = return ()++instance MonadTest IO++instance MonadTest m => MonadTest (ReaderT e m) where+ exploreRaces = lift exploreRaces+
+ io-classes/Control/Monad/Class/MonadThrow.hs view
@@ -0,0 +1,328 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE TypeFamilies #-}++-- | A generalisation of+-- <https://hackage.haskell.org/package/base/docs/Control-Exception.html Control.Exception>+-- API to both 'IO' and <https://hackage.haskell.org/package/io-sim IOSim>.+--+module Control.Monad.Class.MonadThrow+ ( MonadThrow (..)+ , MonadCatch (..)+ , MonadMask (..)+ , MonadMaskingState+ , MonadEvaluate (..)+ , MaskingState (..)+ , Exception (..)+ , SomeException+ , ExitCase (..)+ , Handler (..)+ , catches+ ) where++import Control.Exception (Exception (..), MaskingState, SomeException)+import Control.Exception qualified as IO+import Control.Monad (liftM)++import Control.Monad.Reader (ReaderT (..), lift, runReaderT)++import Control.Monad.STM (STM)+import Control.Monad.STM qualified as STM++#if __GLASGOW_HASKELL__ >= 910+import GHC.Internal.Exception.Context (ExceptionAnnotation)+#endif++-- | Throwing exceptions, and resource handling in the presence of exceptions.+--+-- Does not include the ability to respond to exceptions.+--+class Monad m => MonadThrow m where++#if __GLASGOW_HASKELL__ >= 910+ {-# MINIMAL throwIO, annotateIO #-}+#else+ {-# MINIMAL throwIO #-}+#endif++ throwIO :: Exception e => e -> m a++ bracket :: m a -> (a -> m b) -> (a -> m c) -> m c+ bracket_ :: m a -> m b -> m c -> m c+ finally :: m a -> m b -> m a+#if __GLASGOW_HASKELL__ >= 910+ -- | See 'IO.annotateIO'.+ --+ -- @since 1.5.0.0+ annotateIO :: forall e a. ExceptionAnnotation e => e -> m a -> m a+#endif++ default bracket :: MonadCatch m => m a -> (a -> m b) -> (a -> m c) -> m c++ bracket before after =+ liftM fst .+ generalBracket+ before+ (\a _exitCase -> after a)++ bracket_ before after thing = bracket before (const after) (const thing)++ a `finally` sequel =+ bracket_ (return ()) sequel a++-- | Catching exceptions.+--+-- Covers standard utilities to respond to exceptions.+--+class MonadThrow m => MonadCatch m where++ {-# MINIMAL catch #-}++ catch :: Exception e => m a -> (e -> m a) -> m a+ catchJust :: Exception e => (e -> Maybe b) -> m a -> (b -> m a) -> m a++ try :: Exception e => m a -> m (Either e a)+ tryJust :: Exception e => (e -> Maybe b) -> m a -> m (Either b a)++ handle :: Exception e => (e -> m a) -> m a -> m a+ handleJust :: Exception e => (e -> Maybe b) -> (b -> m a) -> m a -> m a++ onException :: m a -> m b -> m a+ bracketOnError :: m a -> (a -> m b) -> (a -> m c) -> m c++ -- | General form of bracket+ --+ -- See <http://hackage.haskell.org/package/exceptions-0.10.0/docs/Control-Monad-Catch.html#v:generalBracket>+ -- for discussion and motivation.+ generalBracket :: m a -> (a -> ExitCase b -> m c) -> (a -> m b) -> m (b, c)++ default generalBracket+ :: MonadMask m+ => m a -> (a -> ExitCase b -> m c) -> (a -> m b) -> m (b, c)++ catchJust p a handler =+ catch a handler'+ where+ handler' e = case p e of+ Nothing -> throwIO e+ Just b -> handler b++ try a = catch (Right `fmap` a) (return . Left)++ tryJust p a = do+ r <- try a+ case r of+ Right v -> return (Right v)+ Left e -> case p e of+ Nothing -> throwIO e+ Just b -> return (Left b)++ handle = flip catch+ handleJust p = flip (catchJust p)++ onException action what =+ action `catch` \e -> do+ _ <- what+ throwIO (e :: SomeException)++ bracketOnError acquire release = liftM fst . generalBracket+ acquire+ (\a exitCase -> case exitCase of+ ExitCaseSuccess _ -> return ()+ _ -> do+ _ <- release a+ return ())++ generalBracket acquire release use =+ mask $ \unmasked -> do+ resource <- acquire+ b <- unmasked (use resource) `catch` \e -> do+ _ <- release resource (ExitCaseException e)+ throwIO e+ c <- release resource (ExitCaseSuccess b)+ return (b, c)+++-- | The default handler type for 'catches', whcih is a generalisation of+-- 'IO.Handler'.+--+data Handler m a = forall e. Exception e => Handler (e -> m a)++deriving instance (Functor m) => Functor (Handler m)++-- | Like 'catches' but for 'MonadCatch' rather than only 'IO'.+--+catches :: forall m a. MonadCatch m+ => m a -> [Handler m a] -> m a+catches ma handlers = ma `catch` catchesHandler handlers+{-# SPECIALISE catches :: IO a -> [Handler IO a] -> IO a #-}++-- | Used in the default 'catches' implementation.+--+catchesHandler :: MonadCatch m+ => [Handler m a]+ -> SomeException+ -> m a+catchesHandler handlers e = foldr tryHandler (throwIO e) handlers+ where tryHandler (Handler handler) res+ = case fromException e of+ Just e' -> handler e'+ Nothing -> res+{-# SPECIALISE catchesHandler :: [Handler IO a] -> SomeException -> IO a #-}+++-- | Used in 'generalBracket'+--+-- See @exceptions@ package for discussion and motivation.+data ExitCase a+ = ExitCaseSuccess a+ | ExitCaseException SomeException+ | ExitCaseAbort+ deriving (Show, Functor)++-- | Support for safely working in the presence of asynchronous exceptions.+--+-- This is typically not needed directly as the utilities in 'MonadThrow' and+-- 'MonadCatch' cover most use cases.+--+class MonadCatch m => MonadMask m where++ {-# MINIMAL mask,+ uninterruptibleMask,+ getMaskingState,+ interruptible #-}++ mask, uninterruptibleMask :: ((forall a. m a -> m a) -> m b) -> m b++ mask_, uninterruptibleMask_ :: m a -> m a+ mask_ action = mask $ \_ -> action+ uninterruptibleMask_ action = uninterruptibleMask $ \_ -> action++ getMaskingState :: m MaskingState+ interruptible :: m a -> m a++ allowInterrupt :: m ()+ allowInterrupt = interruptible (return ())++class MonadMask m => MonadMaskingState m+{-# DEPRECATED MonadMaskingState "Use MonadMask instead" #-}+++-- | Monads which can 'evaluate'.+--+class MonadEvaluate m where+ evaluate :: a -> m a++--+-- Instance for IO uses the existing base library implementations+--++instance MonadThrow IO where++ throwIO = IO.throwIO++ bracket = IO.bracket+ bracket_ = IO.bracket_+ finally = IO.finally+#if __GLASGOW_HASKELL__ >= 910+ annotateIO = IO.annotateIO+#endif+++instance MonadCatch IO where++ catch = IO.catch++ catchJust = IO.catchJust+ try = IO.try+ tryJust = IO.tryJust+ handle = IO.handle+ handleJust = IO.handleJust+ onException = IO.onException+ bracketOnError = IO.bracketOnError+ -- use default implementation of 'generalBracket' (base does not define one)+++instance MonadMask IO where++ mask = IO.mask+ mask_ = IO.mask_++ uninterruptibleMask = IO.uninterruptibleMask+ uninterruptibleMask_ = IO.uninterruptibleMask_++ getMaskingState = IO.getMaskingState+ interruptible = IO.interruptible+ allowInterrupt = IO.allowInterrupt++instance MonadMaskingState IO++instance MonadEvaluate IO where+ evaluate = IO.evaluate++--+-- Instance for STM uses STM primitives and default implementations+--++instance MonadThrow STM where+ throwIO = STM.throwSTM+#if __GLASGOW_HASKELL__ >= 910+ annotateIO ann io = io `catch` \e -> throwIO (IO.addExceptionContext ann e)+#endif++instance MonadCatch STM where+ catch = STM.catchSTM++ generalBracket acquire release use = do+ resource <- acquire+ b <- use resource `catch` \e -> do+ _ <- release resource (ExitCaseException e)+ throwIO e+ c <- release resource (ExitCaseSuccess b)+ return (b, c)+++--+-- ReaderT instances+--++instance MonadThrow m => MonadThrow (ReaderT r m) where+ throwIO = lift . throwIO+ bracket acquire release use = ReaderT $ \env ->+ bracket+ ( runReaderT acquire env)+ (\a -> runReaderT (release a) env)+ (\a -> runReaderT (use a) env)+#if __GLASGOW_HASKELL__ >= 910+ annotateIO ann io = ReaderT $ \env ->+ annotateIO ann (runReaderT io env)+#endif++instance MonadCatch m => MonadCatch (ReaderT r m) where+ catch act handler = ReaderT $ \env ->+ catch+ ( runReaderT act env)+ (\e -> runReaderT (handler e) env)++ generalBracket acquire release use = ReaderT $ \env ->+ generalBracket+ ( runReaderT acquire env)+ (\a e -> runReaderT (release a e) env)+ (\a -> runReaderT (use a) env)++instance MonadMask m => MonadMask (ReaderT r m) where+ mask a = ReaderT $ \e -> mask $ \u -> runReaderT (a $ q u) e+ where q :: (m a -> m a) -> ReaderT e m a -> ReaderT e m a+ q u (ReaderT b) = ReaderT (u . b)+ uninterruptibleMask a =+ ReaderT $ \e -> uninterruptibleMask $ \u -> runReaderT (a $ q u) e+ where q :: (m a -> m a) -> ReaderT e m a -> ReaderT e m a+ q u (ReaderT b) = ReaderT (u . b)++ getMaskingState = lift getMaskingState+ interruptible a =+ ReaderT $ \e -> interruptible (runReaderT a e)+ allowInterrupt = lift allowInterrupt++instance (Monad m, MonadEvaluate m) => MonadEvaluate (ReaderT r m) where+ evaluate = lift . evaluate
+ io-classes/Control/Monad/Class/MonadTime.hs view
@@ -0,0 +1,55 @@+-- | <https://hackage.haskell.org/package/time time> and+-- <https://hackage.haskell.org/package/base base> time API compatible with both+-- 'IO' and <https://hackage.haskell.org/package/io-sim IOSim>.+--+module Control.Monad.Class.MonadTime+ ( MonadTime (..)+ , MonadMonotonicTimeNSec (..)+ -- * 'NominalTime' and its action on 'UTCTime'+ , UTCTime+ , diffUTCTime+ , addUTCTime+ , NominalDiffTime+ ) where++import Control.Monad.Reader++import Data.Time.Clock (NominalDiffTime, UTCTime, addUTCTime, diffUTCTime)+import Data.Time.Clock qualified as Time+import Data.Word (Word64)+import GHC.Clock qualified as IO (getMonotonicTimeNSec)+++class Monad m => MonadMonotonicTimeNSec m where+ -- | Time in a monotonic clock, with high precision. The epoch for this+ -- clock is arbitrary and does not correspond to any wall clock or calendar.+ --+ -- The time is measured in nano seconds as does `getMonotonicTimeNSec` from+ -- "base".+ --+ getMonotonicTimeNSec :: m Word64++class Monad m => MonadTime m where+ -- | Wall clock time.+ --+ getCurrentTime :: m UTCTime++--+-- Instances for IO+--++instance MonadMonotonicTimeNSec IO where+ getMonotonicTimeNSec = IO.getMonotonicTimeNSec++instance MonadTime IO where+ getCurrentTime = Time.getCurrentTime++--+-- MTL instances+--++instance MonadMonotonicTimeNSec m => MonadMonotonicTimeNSec (ReaderT r m) where+ getMonotonicTimeNSec = lift getMonotonicTimeNSec++instance MonadTime m => MonadTime (ReaderT r m) where+ getCurrentTime = lift getCurrentTime
+ io-classes/Control/Monad/Class/MonadTimer.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE TypeFamilies #-}++-- | Provides classes to handle delays and timeouts which generalised+-- <https://hackage.haskell.org/package/base base> API to both 'IO' and+-- <https://hackage.haskell.org/package/io-sim IOSim>.+--+module Control.Monad.Class.MonadTimer+ ( MonadDelay (..)+ , MonadTimer (..)+ ) where++import Control.Concurrent qualified as IO+import Control.Concurrent.Class.MonadSTM+import Control.Concurrent.STM.TVar qualified as STM++import Control.Monad.Reader (ReaderT (..))+import Control.Monad.Trans (lift)++import System.Timeout qualified as IO++-- | A typeclass to delay current thread.+class Monad m => MonadDelay m where++ -- | Suspends the current thread for a given number of microseconds+ -- (GHC only).+ --+ -- See `IO.threadDelay`.+ threadDelay :: Int -> m ()++-- | A typeclass providing utilities for /timeouts/.+class (MonadDelay m, MonadSTM m) => MonadTimer m where++ -- | See `STM.registerDelay`.+ registerDelay :: Int -> m (TVar m Bool)++ -- | See `IO.timeout`.+ timeout :: Int -> m a -> m (Maybe a)++--+-- Instances for IO+--++instance MonadDelay IO where+ threadDelay = IO.threadDelay+++instance MonadTimer IO where++ registerDelay = STM.registerDelay+ timeout = IO.timeout++--+-- Transformer's instances+--++instance MonadDelay m => MonadDelay (ReaderT r m) where+ threadDelay = lift . threadDelay++instance MonadTimer m => MonadTimer (ReaderT r m) where+ registerDelay = lift . registerDelay+ timeout d f = ReaderT $ \r -> timeout d (runReaderT f r)
+ io-classes/Control/Monad/Class/MonadUnique.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE TypeFamilyDependencies #-}++-- | A generalisation of the+-- <https://hackage.haskell.org/package/base/docs/Data-Unique.html Data.Unique>+-- API to both 'IO' and <https://hackage.haskell.org/package/io-sim IOSim>.+--+module Control.Monad.Class.MonadUnique+ ( MonadUnique (..)+ , UniqueFor (..)+ ) where++-- base+import Data.Kind (Type)+import Data.Unique qualified as IO++-- transformers+import Control.Monad.Reader (MonadTrans (..), ReaderT (..), lift)+++class (Monad m, Eq (Unique m), Ord (Unique m)) => MonadUnique m where+ type Unique m = (unique :: Type) | unique -> m+ newUnique :: m (Unique m)+ hashUnique :: Unique m -> Int++ default+ newUnique+ :: (m ~ t n, Unique m ~ UniqueFor t n, MonadTrans t, MonadUnique n)+ => m (Unique m)+ default+ hashUnique+ :: (m ~ t n, Unique m ~ UniqueFor t n, MonadUnique n)+ => Unique m -> Int+ newUnique = lift (MkUniqueFor <$> newUnique)+ hashUnique = hashUnique . unMkUniqueFor++instance MonadUnique IO where+ type Unique IO = IO.Unique+ newUnique = IO.newUnique+ hashUnique = IO.hashUnique+++newtype UniqueFor t m = MkUniqueFor{ unMkUniqueFor :: Unique m }+deriving instance MonadUnique m => Eq (UniqueFor r m)+deriving instance MonadUnique m => Ord (UniqueFor r m)++instance MonadUnique m => MonadUnique (ReaderT r m) where+ type Unique (ReaderT r m) = UniqueFor (ReaderT r) m
+ mtl/Control/Monad/Class/MonadUnique/Trans.hs view
@@ -0,0 +1,40 @@+{-# OPTIONS_GHC -Wno-orphans #-}+{-# LANGUAGE TypeFamilies #-}++module Control.Monad.Class.MonadUnique.Trans () where++import Control.Monad.Cont (ContT)+import Control.Monad.Except (ExceptT)+import Control.Monad.RWS.Lazy qualified as Lazy+import Control.Monad.RWS.Strict qualified as Strict+import Control.Monad.State.Lazy qualified as Lazy+import Control.Monad.State.Strict qualified as Strict+import Control.Monad.Writer.Lazy qualified as Lazy+import Control.Monad.Writer.Strict qualified as Strict++import Control.Monad.Class.MonadUnique+++instance MonadUnique m => MonadUnique (ContT r m) where+ type Unique (ContT r m) = UniqueFor (ContT r) m++instance MonadUnique m => MonadUnique (ExceptT e m) where+ type Unique (ExceptT e m) = UniqueFor (ExceptT e) m++instance (MonadUnique m, Monoid w) => MonadUnique (Lazy.RWST r w s m) where+ type Unique (Lazy.RWST r w s m) = UniqueFor (Lazy.RWST r w s) m++instance (MonadUnique m, Monoid w) => MonadUnique (Strict.RWST r w s m) where+ type Unique (Strict.RWST r w s m) = UniqueFor (Strict.RWST r w s) m++instance MonadUnique m => MonadUnique (Lazy.StateT s m) where+ type Unique (Lazy.StateT s m) = UniqueFor (Lazy.StateT s) m++instance MonadUnique m => MonadUnique (Strict.StateT s m) where+ type Unique (Strict.StateT s m) = UniqueFor (Strict.StateT s) m++instance (MonadUnique m, Monoid w) => MonadUnique (Lazy.WriterT w m) where+ type Unique (Lazy.WriterT w m) = UniqueFor (Lazy.WriterT w) m++instance (MonadUnique m, Monoid w) => MonadUnique (Strict.WriterT w m) where+ type Unique (Strict.WriterT w m) = UniqueFor (Strict.WriterT w) m
si-timers/src/Control/Monad/Class/MonadTime/SI.hs view
@@ -26,22 +26,26 @@ import NoThunks.Class (NoThunks (..)) +import Data.Fixed (Pico, showFixed) import Data.Time.Clock (DiffTime) import Data.Time.Clock qualified as Time import Data.Word (Word64) import GHC.Generics (Generic (..)) --- | A point in time in a monotonic clock.+-- | A point in time in a monotonic clock counted in seconds. -- -- The epoch for this clock is arbitrary and does not correspond to any wall -- clock or calendar, and is /not guaranteed/ to be the same epoch across -- program runs. It is represented as the 'DiffTime' from this arbitrary epoch. -- newtype Time = Time DiffTime- deriving stock (Eq, Ord, Show, Generic)+ deriving stock (Eq, Ord, Generic) deriving newtype NFData deriving anyclass NoThunks++instance Show Time where+ show (Time t) = "Time " ++ showFixed True (realToFrac t :: Pico) -- | The time duration between two points in time (positive or negative). diffTime :: Time -> Time -> DiffTime
si-timers/src/Control/Monad/Class/MonadTimer/SI.hs view
@@ -5,6 +5,7 @@ -- * Auxiliary functions , diffTimeToMicrosecondsAsInt , microsecondsAsIntToDiffTime+ , roundDiffTimeToMicroseconds -- * Re-exports , DiffTime , MonadFork@@ -54,9 +55,24 @@ microsecondsAsIntToDiffTime :: Int -> DiffTime microsecondsAsIntToDiffTime = (/ 1_000_000) . fromIntegral +-- | Round to microseconds.+--+-- For negative diff times it rounds towards negative infinity, which is+-- desirable for `MonadTimer` API.+--+roundDiffTimeToMicroseconds :: DiffTime -> DiffTime+roundDiffTimeToMicroseconds d = fromIntegral usec / 1_000_000+ where+ -- microseconds+ usec :: Integer+ usec = diffTimeToPicoseconds d `div` 1_000_000++ class ( MonadTimer.MonadDelay m , MonadMonotonicTime m ) => MonadDelay m where+ -- | All instances SHOULD round delays down to the nearest microsecond so the+ -- behaviour matches the `IO` instance. threadDelay :: DiffTime -> m () -- | Thread delay. This implementation will not over- or underflow.@@ -68,6 +84,9 @@ -- For delays smaller than `minBound :: Int` seconds, `minBound :: Int` will be -- used instead. --+-- NOTE: since `MonadTimer.threadDelay` uses microsecond precision (as does+-- GHC), so does this instance.+-- instance MonadDelay IO where threadDelay :: forall m. MonadDelay m@@ -103,6 +122,11 @@ instance MonadDelay m => MonadDelay (ReaderT r m) where threadDelay = lift . threadDelay +-- | `MonadTimer` API based on SI units (seconds).+--+-- NOTE: all instances SHOULD round delays down to the nearest microsecond so+-- the behaviour matches the `IO` instance.+-- class ( MonadTimer.MonadTimer m , MonadMonotonicTime m ) => MonadTimer m where
si-timers/test/Test/MonadTimer.hs view
@@ -17,6 +17,8 @@ prop_diffTimeToMicrosecondsAsIntLeftInverse , testProperty "diffTimeToMicroseconds right inverse" prop_diffTimeToMicrosecondsAsIntRightInverse+ , testProperty "roundToMicroseconds"+ prop_roundDiffTimeToMicroseconds ] newtype IntDistr = IntDistr Int@@ -88,3 +90,21 @@ -> "large" | otherwise -> "average"+++prop_roundDiffTimeToMicroseconds :: DiffTimeDistr -> Property+prop_roundDiffTimeToMicroseconds (DiffTimeDistr d) =+ -- rounded is less or equal to d+ --+ -- NOTE: this guarantees that if `d < 0` then `d' < 0` which is+ -- important for `MonadTimer (IOSim s)` instance.+ d' <= d+ .&&.+ -- difference is less than 1 microsecond+ abs (d - d') < 0.000_001+ .&&.+ -- rounded has no fractional microseconds+ case properFraction (d' * 1_000_000) of+ (_ :: Integer, f) -> f === 0+ where+ d' = roundDiffTimeToMicroseconds d
− src/Control/Concurrent/Class/MonadMVar.hs
@@ -1,234 +0,0 @@-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE TypeFamilyDependencies #-}--module Control.Concurrent.Class.MonadMVar- ( MonadMVar (..)- -- * non-standard extensions- , MonadInspectMVar (..)- , MonadTraceMVar (..)- , MonadLabelledMVar (..)- ) where--import Control.Concurrent.MVar qualified as IO-import Control.Monad.Class.MonadThrow--import Control.Monad.Reader (ReaderT (..))-import Control.Monad.Trans (lift)--import Control.Concurrent.Class.MonadSTM (TraceValue)-import Data.Kind (Type)---class Monad m => MonadMVar m where- {-# MINIMAL newEmptyMVar,- takeMVar, tryTakeMVar,- putMVar, tryPutMVar,- readMVar, tryReadMVar,- isEmptyMVar #-}-- type MVar m :: Type -> Type-- -- | See 'IO.newEmptyMVar'.- newEmptyMVar :: m (MVar m a)- -- | See 'IO.takeMVar'.- takeMVar :: MVar m a -> m a- -- | See 'IO.putMVar'.- putMVar :: MVar m a -> a -> m ()- -- | See 'IO.tryTakeMVar'.- tryTakeMVar :: MVar m a -> m (Maybe a)- -- | See 'IO.tryPutMVar'.- tryPutMVar :: MVar m a -> a -> m Bool- -- | See 'IO.isEmptyMVar'.- isEmptyMVar :: MVar m a -> m Bool-- -- methods with a default implementation- -- | See 'IO.newMVar'.- newMVar :: a -> m (MVar m a)- -- | See 'IO.readMVar'.- readMVar :: MVar m a -> m a- -- | See 'IO.tryReadMVar'.- tryReadMVar :: MVar m a -> m (Maybe a)- -- | See 'IO.swapMVar'.- swapMVar :: MVar m a -> a -> m a- -- | See 'IO.withMVar'.- withMVar :: MVar m a -> (a -> m b) -> m b- -- | See 'IO.withMVarMasked'.- withMVarMasked :: MVar m a -> (a -> m b) -> m b- -- | See 'IO.modifyMVar_'.- modifyMVar_ :: MVar m a -> (a -> m a) -> m ()- -- | See 'IO.modifyMVar'.- modifyMVar :: MVar m a -> (a -> m (a, b)) -> m b- -- | See 'IO.modifyMVarMasked_'.- modifyMVarMasked_ :: MVar m a -> (a -> m a) -> m ()- -- | See 'IO.modifyMVarMasked'.- modifyMVarMasked :: MVar m a -> (a -> m (a,b)) -> m b-- default newMVar :: a -> m (MVar m a)- newMVar a = do- v <- newEmptyMVar- putMVar v a- return v- {-# INLINE newMVar #-}-- default swapMVar :: MonadMask m => MVar m a -> a -> m a- swapMVar mvar new =- mask_ $ do- old <- takeMVar mvar- putMVar mvar new- return old- {-# INLINE swapMVar #-}-- default withMVar :: MonadMask m => MVar m a -> (a -> m b) -> m b- withMVar m io =- mask $ \restore -> do- a <- takeMVar m- b <- restore (io a) `onException` putMVar m a- putMVar m a- return b- {-# INLINE withMVar #-}-- default withMVarMasked :: MonadMask m => MVar m a -> (a -> m b) -> m b- withMVarMasked m io =- mask_ $ do- a <- takeMVar m- b <- io a `onException` putMVar m a- putMVar m a- return b- {-# INLINE withMVarMasked #-}-- default modifyMVar_ :: MonadMask m => MVar m a -> (a -> m a) -> m ()- modifyMVar_ m io =- mask $ \restore -> do- a <- takeMVar m- a' <- restore (io a) `onException` putMVar m a- putMVar m a'- {-# INLINE modifyMVar_ #-}-- default modifyMVar :: (MonadMask m, MonadEvaluate m)- => MVar m a -> (a -> m (a,b)) -> m b- modifyMVar m io =- mask $ \restore -> do- a <- takeMVar m- (a',b) <- restore (io a >>= evaluate) `onException` putMVar m a- putMVar m a'- return b- {-# INLINE modifyMVar #-}-- default modifyMVarMasked_ :: MonadMask m => MVar m a -> (a -> m a) -> m ()- modifyMVarMasked_ m io =- mask_ $ do- a <- takeMVar m- a' <- io a `onException` putMVar m a- putMVar m a'- {-# INLINE modifyMVarMasked_ #-}-- default modifyMVarMasked :: (MonadMask m, MonadEvaluate m)- => MVar m a -> (a -> m (a,b)) -> m b- modifyMVarMasked m io =- mask_ $ do- a <- takeMVar m- (a',b) <- (io a >>= evaluate) `onException` putMVar m a- putMVar m a'- return b- {-# INLINE modifyMVarMasked #-}------- IO instance-----instance MonadMVar IO where- type MVar IO = IO.MVar- newEmptyMVar = IO.newEmptyMVar- newMVar = IO.newMVar- takeMVar = IO.takeMVar- putMVar = IO.putMVar- readMVar = IO.readMVar- swapMVar = IO.swapMVar- tryTakeMVar = IO.tryTakeMVar- tryPutMVar = IO.tryPutMVar- tryReadMVar = IO.tryReadMVar- isEmptyMVar = IO.isEmptyMVar- withMVar = IO.withMVar- withMVarMasked = IO.withMVarMasked- modifyMVar_ = IO.modifyMVar_- modifyMVar = IO.modifyMVar- modifyMVarMasked_ = IO.modifyMVarMasked_- modifyMVarMasked = IO.modifyMVarMasked------- ReaderT instance-----newtype WrappedMVar r (m :: Type -> Type) a = WrappedMVar { unwrapMVar :: MVar m a }--instance ( MonadMask m- , MonadMVar m- ) => MonadMVar (ReaderT r m) where- type MVar (ReaderT r m) = WrappedMVar r m- newEmptyMVar = WrappedMVar <$> lift newEmptyMVar- newMVar = fmap WrappedMVar . lift . newMVar- takeMVar = lift . takeMVar . unwrapMVar- putMVar = lift .: (putMVar . unwrapMVar)- readMVar = lift . readMVar . unwrapMVar- tryReadMVar = lift . tryReadMVar . unwrapMVar- swapMVar = lift .: (swapMVar . unwrapMVar)- tryTakeMVar = lift . tryTakeMVar . unwrapMVar- tryPutMVar = lift .: (tryPutMVar . unwrapMVar)- isEmptyMVar = lift . isEmptyMVar . unwrapMVar- withMVar (WrappedMVar v) f = ReaderT $ \r ->- withMVar v (\a -> runReaderT (f a) r)- withMVarMasked (WrappedMVar v) f = ReaderT $ \r ->- withMVarMasked v (\a -> runReaderT (f a) r)- modifyMVar_ (WrappedMVar v) f = ReaderT $ \r ->- modifyMVar_ v (\a -> runReaderT (f a) r)- modifyMVar (WrappedMVar v) f = ReaderT $ \r ->- modifyMVar v (\a -> runReaderT (f a) r)- modifyMVarMasked_ (WrappedMVar v) f = ReaderT $ \r ->- modifyMVarMasked_ v (\a -> runReaderT (f a) r)- modifyMVarMasked (WrappedMVar v) f = ReaderT $ \r ->- modifyMVarMasked v (\a -> runReaderT (f a) r)------- MonadInspectMVar------- | This type class is intended for--- ['io-sim'](https://hackage.haskell.org/package/io-sim), where one might want--- to access an 'MVar' in the underlying 'ST' monad.-class (MonadMVar m, Monad (InspectMVarMonad m)) => MonadInspectMVar m where- type InspectMVarMonad m :: Type -> Type- -- | Return the value of an 'MVar' as an 'InspectMVarMonad' computation. Can- -- be 'Nothing' if the 'MVar' is empty.- inspectMVar :: proxy m -> MVar m a -> InspectMVarMonad m (Maybe a)--instance MonadInspectMVar IO where- type InspectMVarMonad IO = IO- inspectMVar _ = tryReadMVar--class MonadTraceMVar m where- traceMVarIO :: proxy- -> MVar m a- -> (Maybe (Maybe a) -> Maybe a -> InspectMVarMonad m TraceValue)- -> m ()--instance MonadTraceMVar IO where- traceMVarIO = \_ _ _ -> pure ()---- | Labelled `MVar`s------ The `IO` instances is no-op, the `IOSim` instance enhances simulation trace.--- This is very useful when analysing low lever concurrency issues (e.g.--- deadlocks, livelocks etc).-class MonadMVar m- => MonadLabelledMVar m where- -- | Name an `MVar`- labelMVar :: MVar m a -> String -> m ()--instance MonadLabelledMVar IO where- labelMVar = \_ _ -> pure ()------ Utilities-----(.:) :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)-(f .: g) x y = f (g x y)
− src/Control/Concurrent/Class/MonadSTM.hs
@@ -1,14 +0,0 @@--- | This module corresponds to "Control.Concurrent.STM" in "stm" package----module Control.Concurrent.Class.MonadSTM- (module STM)- where--import Control.Monad.Class.MonadSTM as STM-import Control.Concurrent.Class.MonadSTM.TVar as STM-import Control.Concurrent.Class.MonadSTM.TMVar as STM-import Control.Concurrent.Class.MonadSTM.TChan as STM-import Control.Concurrent.Class.MonadSTM.TQueue as STM-import Control.Concurrent.Class.MonadSTM.TBQueue as STM-import Control.Concurrent.Class.MonadSTM.TArray as STM-
− src/Control/Concurrent/Class/MonadSTM/TArray.hs
@@ -1,7 +0,0 @@-{-# LANGUAGE ExplicitNamespaces #-}---- | This module corresponds to `Control.Concurrent.STM.TArray` in "stm" package----module Control.Concurrent.Class.MonadSTM.TArray (type TArray) where--import Control.Monad.Class.MonadSTM.Internal
− src/Control/Concurrent/Class/MonadSTM/TBQueue.hs
@@ -1,28 +0,0 @@-{-# LANGUAGE ExplicitNamespaces #-}---- | This module corresponds to `Control.Concurrent.STM.TVar` in "stm" package----module Control.Concurrent.Class.MonadSTM.TBQueue- ( -- * MonadSTM- type TBQueue- , newTBQueue- , newTBQueueIO- , readTBQueue- , tryReadTBQueue- , peekTBQueue- , tryPeekTBQueue- , flushTBQueue- , writeTBQueue- , lengthTBQueue- , isEmptyTBQueue- , isFullTBQueue- , unGetTBQueue- -- * MonadLabelledSTM- , labelTBQueue- , labelTBQueueIO- -- * MonadTraceSTM- , traceTBQueue- , traceTBQueueIO- ) where--import Control.Monad.Class.MonadSTM.Internal
− src/Control/Concurrent/Class/MonadSTM/TChan.hs
@@ -1,26 +0,0 @@-{-# LANGUAGE ExplicitNamespaces #-}---- | This module corresponds to `Control.Concurrent.STM.TChan` in "stm" package----module Control.Concurrent.Class.MonadSTM.TChan- ( -- * MonadSTM- -- ** TChans- type TChan- -- * Construction- , newTChan- , newBroadcastTChan- , newTChanIO- , newBroadcastTChanIO- , dupTChan- , cloneTChan- -- ** Reading and writing- , readTChan- , tryReadTChan- , peekTChan- , tryPeekTChan- , writeTChan- , unGetTChan- , isEmptyTChan- ) where--import Control.Monad.Class.MonadSTM.Internal
− src/Control/Concurrent/Class/MonadSTM/TMVar.hs
@@ -1,31 +0,0 @@-{-# LANGUAGE ExplicitNamespaces #-}---- | This module corresponds to `Control.Concurrent.STM.TMVar` in "stm" package----module Control.Concurrent.Class.MonadSTM.TMVar- ( -- * MonadSTM- type TMVar- , newTMVar- , newEmptyTMVar- , newTMVarIO- , newEmptyTMVarIO- , takeTMVar- , tryTakeTMVar- , putTMVar- , tryPutTMVar- , readTMVar- , tryReadTMVar- , swapTMVar- , writeTMVar- , isEmptyTMVar- -- * MonadLabelledSTM- , labelTMVar- , labelTMVarIO- -- * MonadTraceSTM- , traceTMVar- , traceTMVarIO- , debugTraceTMVar- , debugTraceTMVarIO- ) where--import Control.Monad.Class.MonadSTM.Internal
− src/Control/Concurrent/Class/MonadSTM/TQueue.hs
@@ -1,26 +0,0 @@-{-# LANGUAGE ExplicitNamespaces #-}---- | This module corresponds to `Control.Concurrent.STM.TQueue` in "stm" package----module Control.Concurrent.Class.MonadSTM.TQueue- ( -- * MonadSTM- type TQueue- , newTQueue- , newTQueueIO- , readTQueue- , tryReadTQueue- , peekTQueue- , tryPeekTQueue- , flushTQueue- , writeTQueue- , unGetTQueue- , isEmptyTQueue- -- * MonadLabelledSTM- , labelTQueue- , labelTQueueIO- -- * MonadTraceSTM- , traceTQueue- , traceTQueueIO- ) where--import Control.Monad.Class.MonadSTM.Internal
− src/Control/Concurrent/Class/MonadSTM/TSem.hs
@@ -1,20 +0,0 @@-{-# LANGUAGE ExplicitNamespaces #-}---- | This module corresponds to `Control.Concurrent.STM.TSem` in "stm" package----module Control.Concurrent.Class.MonadSTM.TSem- ( -- * MonadSTM- type TSem- , newTSem- , waitTSem- , signalTSem- , signalTSemN- -- * MonadLabelledSTM- , labelTSem- , labelTSemIO- -- * MonadTraceSTM- , traceTSem- , traceTSemIO- ) where--import Control.Monad.Class.MonadSTM.Internal
− src/Control/Concurrent/Class/MonadSTM/TVar.hs
@@ -1,28 +0,0 @@-{-# LANGUAGE ExplicitNamespaces #-}---- | This module corresponds to `Control.Concurrent.STM.TVar` in "stm" package----module Control.Concurrent.Class.MonadSTM.TVar- ( -- * MonadSTM- type TVar- , newTVar- , newTVarIO- , readTVar- , readTVarIO- , writeTVar- , modifyTVar- , modifyTVar'- , stateTVar- , swapTVar- , check- -- * MonadLabelSTM- , labelTVar- , labelTVarIO- -- * MonadTraceSTM- , traceTVar- , traceTVarIO- , debugTraceTVar- , debugTraceTVarIO- ) where--import Control.Monad.Class.MonadSTM.Internal
− src/Control/Monad/Class/MonadAsync.hs
@@ -1,616 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE TypeFamilyDependencies #-}--- MonadAsync's ReaderT instance is undecidable.-{-# LANGUAGE UndecidableInstances #-}---- | <https://hackage.haskell.org/package/async async> API compatible with both--- 'IO' and <https://hackage.haskell.org/package/io-sim IOSim>.----module Control.Monad.Class.MonadAsync- ( MonadAsync (..)- , AsyncCancelled (..)- , ExceptionInLinkedThread (..)- , link- , linkOnly- , link2- , link2Only- , mapConcurrently- , forConcurrently- , mapConcurrently_- , forConcurrently_- , replicateConcurrently- , replicateConcurrently_- , Concurrently (..)- ) where--import Prelude hiding (read)--#if MIN_VERSION_base(4,18,0)-import Control.Applicative (Alternative (..))-#else-import Control.Applicative (Alternative (..), liftA2)-#endif-import Control.Monad (forever)-import Control.Monad.Class.MonadFork-import Control.Monad.Class.MonadSTM-import Control.Monad.Class.MonadThrow-import Control.Monad.Class.MonadTimer--import Control.Monad.Reader (ReaderT (..))-import Control.Monad.Trans (lift)--import Control.Concurrent.Async (AsyncCancelled (..))-import Control.Concurrent.Async qualified as Async-import Control.Exception qualified as E--import Data.Bifunctor (first)-import Data.Foldable (fold)-import Data.Functor (void)-import Data.Kind (Type)--class ( MonadSTM m- , MonadThread m- ) => MonadAsync m where-- {-# MINIMAL async, asyncBound, asyncOn, asyncThreadId, cancel, cancelWith,- asyncWithUnmask, asyncOnWithUnmask, waitCatchSTM, pollSTM #-}-- -- | An asynchronous action- --- -- See 'Async.Async'.- type Async m = (async :: Type -> Type) | async -> m-- -- | See 'Async.async'.- async :: m a -> m (Async m a)- -- | See 'Async.asyncBound'.- asyncBound :: m a -> m (Async m a)- -- | See 'Async.asyncOn'.- asyncOn :: Int -> m a -> m (Async m a)- -- | See 'Async.asyncThreadId'.- asyncThreadId :: Async m a -> ThreadId m- -- | See 'Async.withAsync'.- withAsync :: m a -> (Async m a -> m b) -> m b- -- | See 'Async.withAsyncBound'.- withAsyncBound :: m a -> (Async m a -> m b) -> m b- -- | See 'Async.withAsyncOn'.- withAsyncOn :: Int -> m a -> (Async m a -> m b) -> m b-- -- | See 'Async.waitSTM'.- waitSTM :: Async m a -> STM m a- -- | See 'Async.pollSTM'.- pollSTM :: Async m a -> STM m (Maybe (Either SomeException a))- -- | See 'Async.waitCatchSTM'.- waitCatchSTM :: Async m a -> STM m (Either SomeException a)-- default waitSTM :: MonadThrow (STM m) => Async m a -> STM m a- waitSTM action = waitCatchSTM action >>= either throwSTM return-- -- | See 'Async.waitAnySTM'.- waitAnySTM :: [Async m a] -> STM m (Async m a, a)- -- | See 'Async.waitAnyCatchSTM'.- waitAnyCatchSTM :: [Async m a] -> STM m (Async m a, Either SomeException a)- -- | See 'Async.waitEitherSTM'.- waitEitherSTM :: Async m a -> Async m b -> STM m (Either a b)- -- | See 'Async.waitEitherSTM_'.- waitEitherSTM_ :: Async m a -> Async m b -> STM m ()- -- | See 'Async.waitEitherCatchSTM'.- waitEitherCatchSTM :: Async m a -> Async m b- -> STM m (Either (Either SomeException a)- (Either SomeException b))- -- | See 'Async.waitBothSTM'.- waitBothSTM :: Async m a -> Async m b -> STM m (a, b)-- -- | See 'Async.wait'.- wait :: Async m a -> m a- -- | See 'Async.poll'.- poll :: Async m a -> m (Maybe (Either SomeException a))- -- | See 'Async.waitCatch'.- waitCatch :: Async m a -> m (Either SomeException a)- -- | See 'Async.cancel'.- cancel :: Async m a -> m ()- -- | See 'Async.cancelWith'.- cancelWith :: Exception e => Async m a -> e -> m ()- -- | See 'Async.uninterruptibleCancel'.- uninterruptibleCancel :: Async m a -> m ()-- -- | See 'Async.waitAny'.- waitAny :: [Async m a] -> m (Async m a, a)- -- | See 'Async.waitAnyCatch'.- waitAnyCatch :: [Async m a] -> m (Async m a, Either SomeException a)- -- | See 'Async.waitAnyCancel'.- waitAnyCancel :: [Async m a] -> m (Async m a, a)- -- | See 'Async.waitAnyCatchCancel'.- waitAnyCatchCancel :: [Async m a] -> m (Async m a, Either SomeException a)- -- | See 'Async.waitEither'.- waitEither :: Async m a -> Async m b -> m (Either a b)-- default waitAnySTM :: MonadThrow (STM m) => [Async m a] -> STM m (Async m a, a)- default waitEitherSTM :: MonadThrow (STM m) => Async m a -> Async m b -> STM m (Either a b)- default waitEitherSTM_ :: MonadThrow (STM m) => Async m a -> Async m b -> STM m ()- default waitBothSTM :: MonadThrow (STM m) => Async m a -> Async m b -> STM m (a, b)-- waitAnySTM as =- foldr orElse retry $- map (\a -> do r <- waitSTM a; return (a, r)) as-- waitAnyCatchSTM as =- foldr orElse retry $- map (\a -> do r <- waitCatchSTM a; return (a, r)) as-- waitEitherSTM left right =- (Left <$> waitSTM left)- `orElse`- (Right <$> waitSTM right)-- waitEitherSTM_ left right =- (void $ waitSTM left)- `orElse`- (void $ waitSTM right)-- waitEitherCatchSTM left right =- (Left <$> waitCatchSTM left)- `orElse`- (Right <$> waitCatchSTM right)-- waitBothSTM left right = do- a <- waitSTM left- `orElse`- (waitSTM right >> retry)- b <- waitSTM right- return (a,b)-- -- | Note, IO-based implementations should override the default- -- implementation. See the @async@ package implementation and comments.- -- <http://hackage.haskell.org/package/async-2.2.1/docs/src/Control.Concurrent.Async.html#waitEitherCatch>- --- -- See 'Async.waitEitherCatch'.- waitEitherCatch :: Async m a -> Async m b -> m (Either (Either SomeException a)- (Either SomeException b))- -- | See 'Async.waitEitherCancel'.- waitEitherCancel :: Async m a -> Async m b -> m (Either a b)- -- | See 'Async.waitEitherCatchCancel'.- waitEitherCatchCancel :: Async m a -> Async m b -> m (Either (Either SomeException a)- (Either SomeException b))- -- | See 'Async.waitEither_'.- waitEither_ :: Async m a -> Async m b -> m ()- -- | See 'Async.waitBoth'.- waitBoth :: Async m a -> Async m b -> m (a, b)-- -- | See 'Async.race'.- race :: m a -> m b -> m (Either a b)- -- | See 'Async.race_'.- race_ :: m a -> m b -> m ()- -- | See 'Async.concurrently'.- concurrently :: m a -> m b -> m (a,b)- -- | See 'Async.concurrently_'.- concurrently_ :: m a -> m b -> m ()-- -- | See 'Async.concurrently_'.- asyncWithUnmask :: ((forall b . m b -> m b) -> m a) -> m (Async m a)- -- | See 'Async.asyncOnWithUnmask'.- asyncOnWithUnmask :: Int -> ((forall b . m b -> m b) -> m a) -> m (Async m a)- -- | See 'Async.withAsyncWithUnmask'.- withAsyncWithUnmask :: ((forall c. m c -> m c) -> m a) -> (Async m a -> m b) -> m b- -- | See 'Async.withAsyncOnWithUnmask'.- withAsyncOnWithUnmask :: Int -> ((forall c. m c -> m c) -> m a) -> (Async m a -> m b) -> m b-- -- | See 'Async.compareAsyncs'.- compareAsyncs :: Async m a -> Async m b -> Ordering-- -- default implementations- default withAsync :: MonadMask m => m a -> (Async m a -> m b) -> m b- default withAsyncBound:: MonadMask m => m a -> (Async m a -> m b) -> m b- default withAsyncOn :: MonadMask m => Int -> m a -> (Async m a -> m b) -> m b- default withAsyncWithUnmask- :: MonadMask m => ((forall c. m c -> m c) -> m a)- -> (Async m a -> m b) -> m b- default withAsyncOnWithUnmask- :: MonadMask m => Int- -> ((forall c. m c -> m c) -> m a)- -> (Async m a -> m b) -> m b- default uninterruptibleCancel- :: MonadMask m => Async m a -> m ()- default waitAnyCancel :: MonadThrow m => [Async m a] -> m (Async m a, a)- default waitAnyCatchCancel :: MonadThrow m => [Async m a]- -> m (Async m a, Either SomeException a)- default waitEitherCancel :: MonadThrow m => Async m a -> Async m b- -> m (Either a b)- default waitEitherCatchCancel :: MonadThrow m => Async m a -> Async m b- -> m (Either (Either SomeException a)- (Either SomeException b))- default compareAsyncs :: Ord (ThreadId m)- => Async m a -> Async m b -> Ordering-- withAsync action inner = mask $ \restore -> do- a <- async (restore action)- restore (inner a)- `finally` uninterruptibleCancel a-- withAsyncBound action inner = mask $ \restore -> do- a <- asyncBound (restore action)- restore (inner a)- `finally` uninterruptibleCancel a-- withAsyncOn n action inner = mask $ \restore -> do- a <- asyncOn n (restore action)- restore (inner a)- `finally` uninterruptibleCancel a--- withAsyncWithUnmask action inner = mask $ \restore -> do- a <- asyncWithUnmask action- restore (inner a)- `finally` uninterruptibleCancel a-- withAsyncOnWithUnmask n action inner = mask $ \restore -> do- a <- asyncOnWithUnmask n action- restore (inner a)- `finally` uninterruptibleCancel a-- wait = atomically . waitSTM- poll = atomically . pollSTM- waitCatch = atomically . waitCatchSTM-- uninterruptibleCancel = uninterruptibleMask_ . cancel-- waitAny = atomically . waitAnySTM- waitAnyCatch = atomically . waitAnyCatchSTM- waitEither left right = atomically (waitEitherSTM left right)- waitEither_ left right = atomically (waitEitherSTM_ left right)- waitEitherCatch left right = atomically (waitEitherCatchSTM left right)- waitBoth left right = atomically (waitBothSTM left right)-- waitAnyCancel asyncs =- waitAny asyncs `finally` mapM_ cancel asyncs-- waitAnyCatchCancel asyncs =- waitAnyCatch asyncs `finally` mapM_ cancel asyncs-- waitEitherCancel left right =- waitEither left right `finally` (cancel left >> cancel right)-- waitEitherCatchCancel left right =- waitEitherCatch left right `finally` (cancel left >> cancel right)-- race left right = withAsync left $ \a ->- withAsync right $ \b ->- waitEither a b-- race_ left right = withAsync left $ \a ->- withAsync right $ \b ->- waitEither_ a b-- concurrently left right = withAsync left $ \a ->- withAsync right $ \b ->- waitBoth a b-- concurrently_ left right = void $ concurrently left right-- compareAsyncs a b = asyncThreadId a `compare` asyncThreadId b---- | Similar to 'Async.Concurrently' but which works for any 'MonadAsync'--- instance.----newtype Concurrently m a = Concurrently { runConcurrently :: m a }--instance Functor m => Functor (Concurrently m) where- fmap f (Concurrently ma) = Concurrently (fmap f ma)--instance MonadAsync m => Applicative (Concurrently m) where- pure = Concurrently . pure-- Concurrently fn <*> Concurrently as =- Concurrently $- (\(f, a) -> f a)- `fmap`- concurrently fn as--instance ( MonadAsync m- , MonadTimer m- ) => Alternative (Concurrently m) where- empty = Concurrently $ forever (threadDelay 86400)- Concurrently as <|> Concurrently bs =- Concurrently $ either id id <$> as `race` bs--instance ( Semigroup a- , MonadAsync m- ) => Semigroup (Concurrently m a) where- (<>) = liftA2 (<>)--instance ( Monoid a- , MonadAsync m- ) => Monoid (Concurrently m a) where- mempty = pure mempty----- | See 'Async.mapConcurrently'.-mapConcurrently :: (Traversable t, MonadAsync m) => (a -> m b) -> t a -> m (t b)-mapConcurrently f = runConcurrently . traverse (Concurrently . f)---- | See 'Async.forConcurrently'.-forConcurrently :: (Traversable t, MonadAsync m) => t a -> (a -> m b) -> m (t b)-forConcurrently = flip mapConcurrently---- | See 'Async.mapConcurrently_'.-mapConcurrently_ :: (Foldable f, MonadAsync m) => (a -> m b) -> f a -> m ()-mapConcurrently_ f = runConcurrently . foldMap (Concurrently . void . f)---- | See 'Async.forConcurrently_'.-forConcurrently_ :: (Foldable f, MonadAsync m) => f a -> (a -> m b) -> m ()-forConcurrently_ = flip mapConcurrently_---- | See 'Async.replicateConcurrently'.-replicateConcurrently :: MonadAsync m => Int -> m a -> m [a]-replicateConcurrently cnt = runConcurrently . sequenceA . replicate cnt . Concurrently---- | See 'Async.replicateConcurrently_'.-replicateConcurrently_ :: MonadAsync m => Int -> m a -> m ()-replicateConcurrently_ cnt = runConcurrently . fold . replicate cnt . Concurrently . void-------- Instance for IO uses the existing async library implementations-----instance MonadAsync IO where-- type Async IO = Async.Async-- async = Async.async- asyncBound = Async.asyncBound- asyncOn = Async.asyncOn- asyncThreadId = Async.asyncThreadId- withAsync = Async.withAsync- withAsyncBound = Async.withAsyncBound- withAsyncOn = Async.withAsyncOn-- waitSTM = Async.waitSTM- pollSTM = Async.pollSTM- waitCatchSTM = Async.waitCatchSTM-- waitAnySTM = Async.waitAnySTM- waitAnyCatchSTM = Async.waitAnyCatchSTM- waitEitherSTM = Async.waitEitherSTM- waitEitherSTM_ = Async.waitEitherSTM_- waitEitherCatchSTM = Async.waitEitherCatchSTM- waitBothSTM = Async.waitBothSTM-- wait = Async.wait- poll = Async.poll- waitCatch = Async.waitCatch- cancel = Async.cancel- cancelWith = Async.cancelWith- uninterruptibleCancel = Async.uninterruptibleCancel-- waitAny = Async.waitAny- waitAnyCatch = Async.waitAnyCatch- waitAnyCancel = Async.waitAnyCancel- waitAnyCatchCancel = Async.waitAnyCatchCancel- waitEither = Async.waitEither- waitEitherCatch = Async.waitEitherCatch- waitEitherCancel = Async.waitEitherCancel- waitEitherCatchCancel = Async.waitEitherCatchCancel- waitEither_ = Async.waitEither_- waitBoth = Async.waitBoth-- race = Async.race- race_ = Async.race_- concurrently = Async.concurrently- concurrently_ = Async.concurrently_-- asyncWithUnmask = Async.asyncWithUnmask- asyncOnWithUnmask = Async.asyncOnWithUnmask- withAsyncWithUnmask = Async.withAsyncWithUnmask- withAsyncOnWithUnmask = Async.withAsyncOnWithUnmask-- compareAsyncs = Async.compareAsyncs-------- Linking------ Adapted from "Control.Concurrent.Async"------ We don't use the implementation of linking from 'Control.Concurrent.Async'--- directly because if we /did/ use the real implementation, then the mock--- implementation and the real implementation would not be able to throw the--- same exception, because the exception type used by the real implementation--- is------ > data ExceptionInLinkedThread =--- > forall a . ExceptionInLinkedThread (Async a) SomeException------ containing a reference to the real 'Async' type.------- | Exception from child thread re-raised in parent thread------ We record the thread ID of the child thread as a 'String'. This avoids--- an @m@ parameter in the type, which is important: 'ExceptionInLinkedThread'--- must be an instance of 'Exception', requiring it to be 'Typeable'; if @m@--- appeared in the type, we would require @m@ to be 'Typeable', which does not--- work with with the simulator, as it would require a 'Typeable' constraint--- on the @s@ parameter of 'IOSim'.-data ExceptionInLinkedThread = ExceptionInLinkedThread String SomeException--instance Show ExceptionInLinkedThread where- showsPrec p (ExceptionInLinkedThread a e) =- showParen (p >= 11) $- showString "ExceptionInLinkedThread " .- showsPrec 11 a .- showString " " .- showsPrec 11 e--instance Exception ExceptionInLinkedThread where- fromException = E.asyncExceptionFromException- toException = E.asyncExceptionToException---- | Like 'Async.link'.-link :: (MonadAsync m, MonadFork m, MonadMask m)- => Async m a -> m ()-link = linkOnly (not . isCancel)---- | Like 'Async.linkOnly'.-linkOnly :: forall m a. (MonadAsync m, MonadFork m, MonadMask m)- => (SomeException -> Bool) -> Async m a -> m ()-linkOnly shouldThrow a = do- tid <- myThreadId- void $ forkRepeat ("linkToOnly " <> show linkedThreadId) $ do- r <- waitCatch a- case r of- Left e | shouldThrow e -> throwTo tid (exceptionInLinkedThread e)- _otherwise -> return ()- where- linkedThreadId :: ThreadId m- linkedThreadId = asyncThreadId a-- exceptionInLinkedThread :: SomeException -> ExceptionInLinkedThread- exceptionInLinkedThread =- ExceptionInLinkedThread (show linkedThreadId)---- | Like 'Async.link2'.-link2 :: (MonadAsync m, MonadFork m, MonadMask m)- => Async m a -> Async m b -> m ()-link2 = link2Only (not . isCancel)---- | Like 'Async.link2Only'.-link2Only :: (MonadAsync m, MonadFork m, MonadMask m)- => (SomeException -> Bool) -> Async m a -> Async m b -> m ()-link2Only shouldThrow left right =- void $ forkRepeat ("link2Only " <> show (tl, tr)) $ do- r <- waitEitherCatch left right- case r of- Left (Left e) | shouldThrow e ->- throwTo tr (ExceptionInLinkedThread (show tl) e)- Right (Left e) | shouldThrow e ->- throwTo tl (ExceptionInLinkedThread (show tr) e)- _ -> return ()- where- tl = asyncThreadId left- tr = asyncThreadId right--isCancel :: SomeException -> Bool-isCancel e- | Just AsyncCancelled <- fromException e = True- | otherwise = False--forkRepeat :: (MonadFork m, MonadMask m) => String -> m a -> m (ThreadId m)-forkRepeat label action =- mask $ \restore ->- let go = do r <- tryAll (restore action)- case r of- Left _ -> go- _ -> return ()- in forkIO (labelThisThread label >> go)--tryAll :: MonadCatch m => m a -> m (Either SomeException a)-tryAll = try-------- ReaderT instance-----newtype AsyncReaderT r (m :: Type -> Type) a =- AsyncReaderT { getAsyncReaderT :: Async m a }--instance ( MonadAsync m- , MonadCatch (STM m)- , MonadFork m- , MonadMask m- ) => MonadAsync (ReaderT r m) where- type Async (ReaderT r m) = AsyncReaderT r m- asyncThreadId (AsyncReaderT a) = asyncThreadId a-- async (ReaderT ma) = ReaderT $ \r -> AsyncReaderT <$> async (ma r)- asyncBound (ReaderT ma) = ReaderT $ \r -> AsyncReaderT <$> asyncBound (ma r)- asyncOn n (ReaderT ma) = ReaderT $ \r -> AsyncReaderT <$> asyncOn n (ma r)- withAsync (ReaderT ma) f = ReaderT $ \r -> withAsync (ma r)- $ \a -> runReaderT (f (AsyncReaderT a)) r- withAsyncBound (ReaderT ma) f = ReaderT $ \r -> withAsyncBound (ma r)- $ \a -> runReaderT (f (AsyncReaderT a)) r- withAsyncOn n (ReaderT ma) f = ReaderT $ \r -> withAsyncOn n (ma r)- $ \a -> runReaderT (f (AsyncReaderT a)) r-- asyncWithUnmask f = ReaderT $ \r -> fmap AsyncReaderT- $ asyncWithUnmask- $ \unmask -> runReaderT (f (liftF unmask)) r- where- liftF :: (m a -> m a) -> ReaderT r m a -> ReaderT r m a- liftF g (ReaderT r) = ReaderT (g . r)-- asyncOnWithUnmask n f = ReaderT $ \r -> fmap AsyncReaderT- $ asyncOnWithUnmask n- $ \unmask -> runReaderT (f (liftF unmask)) r- where- liftF :: (m a -> m a) -> ReaderT r m a -> ReaderT r m a- liftF g (ReaderT r) = ReaderT (g . r)-- withAsyncWithUnmask action f =- ReaderT $ \r -> withAsyncWithUnmask (\unmask -> case action (liftF unmask) of- ReaderT ma -> ma r)- $ \a -> runReaderT (f (AsyncReaderT a)) r- where- liftF :: (m a -> m a) -> ReaderT r m a -> ReaderT r m a- liftF g (ReaderT r) = ReaderT (g . r)-- withAsyncOnWithUnmask n action f =- ReaderT $ \r -> withAsyncOnWithUnmask n (\unmask -> case action (liftF unmask) of- ReaderT ma -> ma r)- $ \a -> runReaderT (f (AsyncReaderT a)) r- where- liftF :: (m a -> m a) -> ReaderT r m a -> ReaderT r m a- liftF g (ReaderT r) = ReaderT (g . r)-- waitCatchSTM = lift . waitCatchSTM . getAsyncReaderT- pollSTM = lift . pollSTM . getAsyncReaderT-- race (ReaderT ma) (ReaderT mb) = ReaderT $ \r -> race (ma r) (mb r)- race_ (ReaderT ma) (ReaderT mb) = ReaderT $ \r -> race_ (ma r) (mb r)- concurrently (ReaderT ma) (ReaderT mb) = ReaderT $ \r -> concurrently (ma r) (mb r)-- wait = lift . wait . getAsyncReaderT- poll = lift . poll . getAsyncReaderT- waitCatch = lift . waitCatch . getAsyncReaderT- cancel = lift . cancel . getAsyncReaderT- uninterruptibleCancel = lift . uninterruptibleCancel- . getAsyncReaderT- cancelWith = (lift .: cancelWith)- . getAsyncReaderT- waitAny = fmap (first AsyncReaderT)- . lift . waitAny- . map getAsyncReaderT- waitAnyCatch = fmap (first AsyncReaderT)- . lift . waitAnyCatch- . map getAsyncReaderT- waitAnyCancel = fmap (first AsyncReaderT)- . lift . waitAnyCancel- . map getAsyncReaderT- waitAnyCatchCancel = fmap (first AsyncReaderT)- . lift . waitAnyCatchCancel- . map getAsyncReaderT- waitEither = on (lift .: waitEither) getAsyncReaderT- waitEitherCatch = on (lift .: waitEitherCatch) getAsyncReaderT- waitEitherCancel = on (lift .: waitEitherCancel) getAsyncReaderT- waitEitherCatchCancel = on (lift .: waitEitherCatchCancel) getAsyncReaderT- waitEither_ = on (lift .: waitEither_) getAsyncReaderT- waitBoth = on (lift .: waitBoth) getAsyncReaderT-------- Utilities-----(.:) :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)-(f .: g) x y = f (g x y)----- | A higher order version of 'Data.Function.on'----on :: (f a -> f b -> c)- -> (forall x. g x -> f x)- -> (g a -> g b -> c)-on f g = \a b -> f (g a) (g b)
− src/Control/Monad/Class/MonadEventlog.hs
@@ -1,34 +0,0 @@-module Control.Monad.Class.MonadEventlog (MonadEventlog (..)) where--import Control.Monad.Reader--import Debug.Trace qualified as IO (traceEventIO, traceMarkerIO)--class Monad m => MonadEventlog m where-- -- | Emits a message to the eventlog, if eventlog profiling is available and- -- enabled at runtime.- traceEventIO :: String -> m ()-- -- | Emits a marker to the eventlog, if eventlog profiling is available and- -- enabled at runtime.- --- -- The 'String' is the name of the marker. The name is just used in the- -- profiling tools to help you keep clear which marker is which.- traceMarkerIO :: String -> m ()------- Instances for IO-----instance MonadEventlog IO where- traceEventIO = IO.traceEventIO- traceMarkerIO = IO.traceMarkerIO------- Instance for ReaderT-----instance MonadEventlog m => MonadEventlog (ReaderT r m) where- traceEventIO = lift . traceEventIO- traceMarkerIO = lift . traceMarkerIO
− src/Control/Monad/Class/MonadFork.hs
@@ -1,95 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE TypeFamilies #-}---- | A generalisation of--- <https://hackage.haskell.org/package/base/docs/Control-Concurrent.html Control.Concurrent>--- API to both 'IO' and <https://hackage.haskell.org/package/io-sim IOSim>.----module Control.Monad.Class.MonadFork- ( MonadThread (..)- , labelThisThread- , MonadFork (..)- ) where--import Control.Concurrent qualified as IO-import Control.Exception (AsyncException (ThreadKilled), Exception,- SomeException)-import Control.Monad.Reader (ReaderT (..), lift)-import Data.Kind (Type)-import GHC.Conc.Sync qualified as IO---class (Monad m, Eq (ThreadId m),- Ord (ThreadId m),- Show (ThreadId m)) => MonadThread m where-- type ThreadId m :: Type-- myThreadId :: m (ThreadId m)- labelThread :: ThreadId m -> String -> m ()-- -- | Requires ghc-9.6.1 or newer.- --- -- @since 1.8.0.0- threadLabel :: ThreadId m -> m (Maybe String)---- | Apply the label to the current thread-labelThisThread :: MonadThread m => String -> m ()-labelThisThread label = myThreadId >>= \tid -> labelThread tid label---class MonadThread m => MonadFork m where-- forkIO :: m () -> m (ThreadId m)- forkOn :: Int -> m () -> m (ThreadId m)- forkIOWithUnmask :: ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)- forkFinally :: m a -> (Either SomeException a -> m ()) -> m (ThreadId m)- throwTo :: Exception e => ThreadId m -> e -> m ()-- killThread :: ThreadId m -> m ()- killThread tid = throwTo tid ThreadKilled-- yield :: m ()-- getNumCapabilities :: m Int---instance MonadThread IO where- type ThreadId IO = IO.ThreadId- myThreadId = IO.myThreadId- labelThread = IO.labelThread-#if MIN_VERSION_base(4,18,0)- threadLabel = IO.threadLabel-#else- threadLabel = \_ -> pure Nothing-#endif--instance MonadFork IO where- forkIO = IO.forkIO- forkOn = IO.forkOn- forkIOWithUnmask = IO.forkIOWithUnmask- forkFinally = IO.forkFinally- throwTo = IO.throwTo- killThread = IO.killThread- yield = IO.yield- getNumCapabilities = IO.getNumCapabilities--instance MonadThread m => MonadThread (ReaderT r m) where- type ThreadId (ReaderT r m) = ThreadId m- myThreadId = lift myThreadId- labelThread t l = lift (labelThread t l)- threadLabel = lift . threadLabel--instance MonadFork m => MonadFork (ReaderT e m) where- forkIO (ReaderT f) = ReaderT $ \e -> forkIO (f e)- forkOn n (ReaderT f) = ReaderT $ \e -> forkOn n (f e)- forkIOWithUnmask k = ReaderT $ \e -> forkIOWithUnmask $ \restore ->- let restore' :: ReaderT e m a -> ReaderT e m a- restore' (ReaderT f) = ReaderT $ restore . f- in runReaderT (k restore') e- forkFinally f k = ReaderT $ \e -> forkFinally (runReaderT f e)- $ \err -> runReaderT (k err) e- throwTo e t = lift (throwTo e t)- yield = lift yield-- getNumCapabilities = lift getNumCapabilities
− src/Control/Monad/Class/MonadST.hs
@@ -1,57 +0,0 @@-module Control.Monad.Class.MonadST (MonadST (..)) where--import Control.Monad.Reader--import Control.Monad.Primitive-import Control.Monad.ST (ST)----- | This class is for abstracting over 'stToIO' which allows running 'ST'--- actions in 'IO'. In this case it is to allow running 'ST' actions within--- another monad @m@.------ The normal type of 'stToIO' is:------ > stToIO :: ST RealWorld a -> IO a------ We have two approaches to abstracting over this, a new and an older--- (deprecated) method. The new method borrows the @primitive@ package's--- 'PrimMonad' and 'PrimState' type family. This gives us:------ > stToIO :: ST (PrimState m) a -> m a------ Which for 'IO' is exactly the same as above. For 'ST' it is identity, while--- for @IOSim@ it is------ > stToIO :: ST s a -> IOSim s a------ The older (deprecated) method is tricky because we need to not care about--- both the @IO@, and also the @RealWorld@, and it does so avoiding mentioning--- any @s@ type (which is what the 'PrimState' type family gives access to).--- The solution is to write an action that is given the @liftST@ as an argument--- and where that action itself is polymorphic in the @s@ parameter. This--- allows us to instantiate it with @RealWorld@ in the @IO@ case, and the local--- @s@ in a case where we are embedding into another @ST@ action.----class PrimMonad m => MonadST m where- -- | @since 1.4.1.0- stToIO :: ST (PrimState m) a -> m a-- -- | Deprecated. Use 'stToIO' instead.- withLiftST :: (forall s. (forall a. ST s a -> m a) -> b) -> b- withLiftST = \k -> k stToIO--{-# DEPRECATED withLiftST "Use the simpler 'stToIO' instead." #-}--instance MonadST IO where- stToIO = stToPrim--instance MonadST (ST s) where- stToIO = stToPrim- withLiftST = \f -> f id--instance (MonadST m, PrimMonad m) => MonadST (ReaderT r m) where- stToIO :: ST (PrimState m) a -> ReaderT r m a- stToIO f = lift (stToPrim f)-- withLiftST f = withLiftST $ \g -> f (lift . g)
− src/Control/Monad/Class/MonadSTM.hs
@@ -1,29 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}--- undecidable instances needed for 'WrappedSTM' instances of 'MonadThrow' and--- 'MonadCatch' type classes.-{-# LANGUAGE UndecidableInstances #-}---- | This module corresponds to "Control.Monad.STM" in "stm" package----module Control.Monad.Class.MonadSTM- ( MonadSTM (STM, atomically, retry, orElse, check)- , throwSTM- -- * non standard extensions- --- -- $non-standard-extensions- , MonadLabelledSTM- , MonadTraceSTM (..)- , TraceValue (..)- , MonadInspectSTM (..)- ) where--import Control.Monad.Class.MonadSTM.Internal---- $non-standard-extensions------ The non standard extensions include `MonadLabelledSTM` and `MonadTraceSTM` /--- `MonadInspectSTM`. For `IO` these are all no-op, however they greatly--- enhance [`IOSim`](https://hackage.haskell.org/package/io-sim) capabilities.--- They are not only useful for debugging concurrency issues, but also to write--- testable properties.
− src/Control/Monad/Class/MonadSTM/Internal.hs
@@ -1,1306 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeFamilyDependencies #-}---- needed for `ReaderT` instance-{-# LANGUAGE UndecidableInstances #-}---- Internal module. It's only exposed as it provides various default types for--- defining new instances, otherwise prefer to use--- 'Control.Concurrent.Class.MonadSTM'.----module Control.Monad.Class.MonadSTM.Internal- ( MonadSTM (..)- , MonadLabelledSTM (..)- , MonadInspectSTM (..)- , TraceValue (TraceValue, TraceDynamic, TraceString, DontTrace, traceDynamic, traceString)- , MonadTraceSTM (..)- -- * MonadThrow aliases- , throwSTM- , catchSTM- -- * Default implementations- -- $default-implementations- --- -- ** Default 'TMVar' implementation- , TMVarDefault (..)- , newTMVarDefault- , newEmptyTMVarDefault- , takeTMVarDefault- , tryTakeTMVarDefault- , putTMVarDefault- , tryPutTMVarDefault- , readTMVarDefault- , tryReadTMVarDefault- , swapTMVarDefault- , writeTMVarDefault- , isEmptyTMVarDefault- , labelTMVarDefault- , traceTMVarDefault- -- ** Default 'TQueue' implementation- , TQueueDefault (..)- , newTQueueDefault- , writeTQueueDefault- , readTQueueDefault- , tryReadTQueueDefault- , isEmptyTQueueDefault- , peekTQueueDefault- , tryPeekTQueueDefault- , flushTQueueDefault- , unGetTQueueDefault- , labelTQueueDefault- -- ** Default 'TBQueue' implementation- , TBQueueDefault (..)- , newTBQueueDefault- , writeTBQueueDefault- , readTBQueueDefault- , tryReadTBQueueDefault- , peekTBQueueDefault- , tryPeekTBQueueDefault- , isEmptyTBQueueDefault- , isFullTBQueueDefault- , lengthTBQueueDefault- , flushTBQueueDefault- , unGetTBQueueDefault- , labelTBQueueDefault- -- ** Default 'TArray' implementation- , TArrayDefault (..)- -- ** Default 'TSem' implementation- , TSemDefault (..)- , newTSemDefault- , waitTSemDefault- , signalTSemDefault- , signalTSemNDefault- , labelTSemDefault- -- ** Default 'TChan' implementation- , TChanDefault (..)- , newTChanDefault- , newBroadcastTChanDefault- , writeTChanDefault- , readTChanDefault- , tryReadTChanDefault- , peekTChanDefault- , tryPeekTChanDefault- , dupTChanDefault- , unGetTChanDefault- , isEmptyTChanDefault- , cloneTChanDefault- , labelTChanDefault- -- * Trace tvar and tmvar- , debugTraceTVar- , debugTraceTVarIO- , debugTraceTMVar- , debugTraceTMVarIO- ) where--import Prelude hiding (read)--import Control.Concurrent.STM.TArray qualified as STM-import Control.Concurrent.STM.TBQueue qualified as STM-import Control.Concurrent.STM.TChan qualified as STM-import Control.Concurrent.STM.TMVar qualified as STM-import Control.Concurrent.STM.TQueue qualified as STM-import Control.Concurrent.STM.TSem qualified as STM-import Control.Concurrent.STM.TVar qualified as STM-import Control.Monad (unless, when)-import Control.Monad.STM qualified as STM--import Control.Monad.Reader (ReaderT (..))-import Control.Monad.Trans (lift)--import Control.Monad.Class.MonadThrow qualified as MonadThrow--import Control.Exception-import Data.Array (Array, bounds)-import Data.Array qualified as Array-import Data.Array.Base (IArray (numElements), MArray (..), arrEleBottom,- listArray, unsafeAt)-import Data.Foldable (traverse_)-import Data.Ix (Ix, rangeSize)-import Data.Kind (Type)-import Data.Proxy (Proxy (..))-import Data.Typeable (Typeable)-import GHC.Stack-import Numeric.Natural (Natural)----- $default-implementations------ The default implementations are based on a `TVar` defined in the class. They--- are tailored towards `IOSim` rather than instances which would like to derive--- from `IO` or monad transformers.----- | The STM primitives parametrised by a monad `m`.----class (Monad m, Monad (STM m)) => MonadSTM m where- -- | The STM monad.- type STM m = (stm :: Type -> Type) | stm -> m- -- | Atomically run an STM computation.- --- -- See `STM.atomically`.- atomically :: HasCallStack => STM m a -> m a-- -- | A type of a 'TVar'.- --- -- See `STM.TVar'.- type TVar m :: Type -> Type-- newTVar :: a -> STM m (TVar m a)- readTVar :: TVar m a -> STM m a- writeTVar :: TVar m a -> a -> STM m ()- -- | See `STM.retry`.- retry :: STM m a- -- | See `STM.orElse`.- orElse :: STM m a -> STM m a -> STM m a-- modifyTVar :: TVar m a -> (a -> a) -> STM m ()- modifyTVar v f = readTVar v >>= writeTVar v . f-- modifyTVar' :: TVar m a -> (a -> a) -> STM m ()- modifyTVar' v f = readTVar v >>= \x -> writeTVar v $! f x-- -- | @since io-classes-0.2.0.0- stateTVar :: TVar m s -> (s -> (a, s)) -> STM m a- stateTVar = stateTVarDefault-- swapTVar :: TVar m a -> a -> STM m a- swapTVar = swapTVarDefault-- -- | See `STM.check`.- check :: Bool -> STM m ()- check True = return ()- check _ = retry-- -- Additional derived STM APIs- type TMVar m :: Type -> Type- newTMVar :: a -> STM m (TMVar m a)- newEmptyTMVar :: STM m (TMVar m a)- takeTMVar :: TMVar m a -> STM m a- tryTakeTMVar :: TMVar m a -> STM m (Maybe a)- putTMVar :: TMVar m a -> a -> STM m ()- tryPutTMVar :: TMVar m a -> a -> STM m Bool- readTMVar :: TMVar m a -> STM m a- tryReadTMVar :: TMVar m a -> STM m (Maybe a)- swapTMVar :: TMVar m a -> a -> STM m a- writeTMVar :: TMVar m a -> a -> STM m ()- isEmptyTMVar :: TMVar m a -> STM m Bool-- type TQueue m :: Type -> Type- newTQueue :: STM m (TQueue m a)- readTQueue :: TQueue m a -> STM m a- tryReadTQueue :: TQueue m a -> STM m (Maybe a)- peekTQueue :: TQueue m a -> STM m a- tryPeekTQueue :: TQueue m a -> STM m (Maybe a)- flushTQueue :: TQueue m a -> STM m [a]- writeTQueue :: TQueue m a -> a -> STM m ()- isEmptyTQueue :: TQueue m a -> STM m Bool- unGetTQueue :: TQueue m a -> a -> STM m ()-- type TBQueue m :: Type -> Type- newTBQueue :: Natural -> STM m (TBQueue m a)- readTBQueue :: TBQueue m a -> STM m a- tryReadTBQueue :: TBQueue m a -> STM m (Maybe a)- peekTBQueue :: TBQueue m a -> STM m a- tryPeekTBQueue :: TBQueue m a -> STM m (Maybe a)- flushTBQueue :: TBQueue m a -> STM m [a]- writeTBQueue :: TBQueue m a -> a -> STM m ()- -- | @since 0.2.0.0- lengthTBQueue :: TBQueue m a -> STM m Natural- isEmptyTBQueue :: TBQueue m a -> STM m Bool- isFullTBQueue :: TBQueue m a -> STM m Bool- unGetTBQueue :: TBQueue m a -> a -> STM m ()-- type TArray m :: Type -> Type -> Type-- type TSem m :: Type- newTSem :: Integer -> STM m (TSem m)- waitTSem :: TSem m -> STM m ()- signalTSem :: TSem m -> STM m ()- signalTSemN :: Natural -> TSem m -> STM m ()-- type TChan m :: Type -> Type- newTChan :: STM m (TChan m a)- newBroadcastTChan :: STM m (TChan m a)- dupTChan :: TChan m a -> STM m (TChan m a)- cloneTChan :: TChan m a -> STM m (TChan m a)- readTChan :: TChan m a -> STM m a- tryReadTChan :: TChan m a -> STM m (Maybe a)- peekTChan :: TChan m a -> STM m a- tryPeekTChan :: TChan m a -> STM m (Maybe a)- writeTChan :: TChan m a -> a -> STM m ()- unGetTChan :: TChan m a -> a -> STM m ()- isEmptyTChan :: TChan m a -> STM m Bool--- -- Helpful derived functions with default implementations-- newTVarIO :: a -> m (TVar m a)- readTVarIO :: TVar m a -> m a- newTMVarIO :: a -> m (TMVar m a)- newEmptyTMVarIO :: m (TMVar m a)- newTQueueIO :: m (TQueue m a)- newTBQueueIO :: Natural -> m (TBQueue m a)- newTChanIO :: m (TChan m a)- newBroadcastTChanIO :: m (TChan m a)-- --- -- default implementations- ---- newTVarIO = atomically . newTVar- readTVarIO = atomically . readTVar- newTMVarIO = atomically . newTMVar- newEmptyTMVarIO = atomically newEmptyTMVar- newTQueueIO = atomically newTQueue- newTBQueueIO = atomically . newTBQueue- newTChanIO = atomically newTChan- newBroadcastTChanIO = atomically newBroadcastTChan----stateTVarDefault :: MonadSTM m => TVar m s -> (s -> (a, s)) -> STM m a-stateTVarDefault var f = do- s <- readTVar var- let (a, s') = f s- writeTVar var s'- return a--swapTVarDefault :: MonadSTM m => TVar m a -> a -> STM m a-swapTVarDefault var new = do- old <- readTVar var- writeTVar var new- return old----- | Labelled `TVar`s & friends.------ The `IO` instances is no-op, the `IOSim` instance enhances simulation trace.--- This is very useful when analysing low lever concurrency issues (e.g.--- deadlocks, livelocks etc).----class MonadSTM m- => MonadLabelledSTM m where- -- | Name a `TVar`.- labelTVar :: TVar m a -> String -> STM m ()- labelTMVar :: TMVar m a -> String -> STM m ()- labelTQueue :: TQueue m a -> String -> STM m ()- labelTBQueue :: TBQueue m a -> String -> STM m ()- labelTArray :: (Ix i, Show i)- => TArray m i e -> String -> STM m ()- labelTSem :: TSem m -> String -> STM m ()- labelTChan :: TChan m a -> String -> STM m ()-- labelTVarIO :: TVar m a -> String -> m ()- labelTMVarIO :: TMVar m a -> String -> m ()- labelTQueueIO :: TQueue m a -> String -> m ()- labelTBQueueIO :: TBQueue m a -> String -> m ()- labelTArrayIO :: (Ix i, Show i)- => TArray m i e -> String -> m ()- labelTSemIO :: TSem m -> String -> m ()- labelTChanIO :: TChan m a -> String -> m ()-- --- -- default implementations- ---- default labelTMVar :: TMVar m ~ TMVarDefault m- => TMVar m a -> String -> STM m ()- labelTMVar = labelTMVarDefault-- default labelTQueue :: TQueue m ~ TQueueDefault m- => TQueue m a -> String -> STM m ()- labelTQueue = labelTQueueDefault-- default labelTBQueue :: TBQueue m ~ TBQueueDefault m- => TBQueue m a -> String -> STM m ()- labelTBQueue = labelTBQueueDefault-- default labelTSem :: TSem m ~ TSemDefault m- => TSem m -> String -> STM m ()- labelTSem = labelTSemDefault-- default labelTChan :: TChan m ~ TChanDefault m- => TChan m a -> String -> STM m ()- labelTChan = labelTChanDefault-- default labelTArray :: ( TArray m ~ TArrayDefault m- , Ix i- , Show i- )- => TArray m i e -> String -> STM m ()- labelTArray = labelTArrayDefault-- default labelTVarIO :: TVar m a -> String -> m ()- labelTVarIO = \v l -> atomically (labelTVar v l)-- default labelTMVarIO :: TMVar m a -> String -> m ()- labelTMVarIO = \v l -> atomically (labelTMVar v l)-- default labelTQueueIO :: TQueue m a -> String -> m ()- labelTQueueIO = \v l -> atomically (labelTQueue v l)-- default labelTBQueueIO :: TBQueue m a -> String -> m ()- labelTBQueueIO = \v l -> atomically (labelTBQueue v l)-- default labelTArrayIO :: (Ix i, Show i)- => TArray m i e -> String -> m ()- labelTArrayIO = \v l -> atomically (labelTArray v l)-- default labelTSemIO :: TSem m -> String -> m ()- labelTSemIO = \v l -> atomically (labelTSem v l)-- default labelTChanIO :: TChan m a -> String -> m ()- labelTChanIO = \v l -> atomically (labelTChan v l)----- | This type class is indented for--- ['io-sim'](https://hackage.haskell.org/package/io-sim), where one might want--- to access a 'TVar' in the underlying 'ST' monad.----class ( MonadSTM m- , Monad (InspectMonadSTM m)- )- => MonadInspectSTM m where- type InspectMonadSTM m :: Type -> Type- -- | Return the value of a `TVar` as an `InspectMonad` computation.- --- -- `inspectTVar` is useful if the value of a `TVar` observed by `traceTVar`- -- contains other `TVar`s.- inspectTVar :: proxy m -> TVar m a -> InspectMonadSTM m a- -- | Return the value of a `TMVar` as an `InspectMonad` computation.- inspectTMVar :: proxy m -> TMVar m a -> InspectMonadSTM m (Maybe a)- -- TODO: inspectTQueue, inspectTBQueue--instance MonadInspectSTM IO where- type InspectMonadSTM IO = IO- inspectTVar _ = readTVarIO- -- issue #3198: tryReadTMVarIO- inspectTMVar _ = atomically . tryReadTMVar----- | A GADT which instructs how to trace the value. The 'traceDynamic' will--- use dynamic tracing, e.g. "Control.Monad.IOSim.traceM"; while 'traceString'--- will be traced with 'EventSay'. The `IOSim`s dynamic tracing allows to--- recover the value from the simulation trace (see--- "Control.Monad.IOSim.selectTraceEventsDynamic").----data TraceValue where- TraceValue :: forall tr. Typeable tr- => { traceDynamic :: Maybe tr- , traceString :: Maybe String- }- -> TraceValue----- | Use only a dynamic tracer.----pattern TraceDynamic :: () => forall tr. Typeable tr => tr -> TraceValue-pattern TraceDynamic tr <- TraceValue { traceDynamic = Just tr }- where- TraceDynamic tr = TraceValue { traceDynamic = Just tr, traceString = Nothing }---- | Use only string tracing.----pattern TraceString :: String -> TraceValue-pattern TraceString tr <- TraceValue { traceString = Just tr }- where- TraceString tr = TraceValue { traceDynamic = (Nothing :: Maybe ())- , traceString = Just tr- }---- | Do not trace the value.----pattern DontTrace :: TraceValue-pattern DontTrace <- TraceValue Nothing Nothing- where- DontTrace = TraceValue (Nothing :: Maybe ()) Nothing---- | 'MonadTraceSTM' allows to trace values of stm variables when stm--- transaction is committed. This allows to verify invariants when a variable--- is committed.----class MonadInspectSTM m- => MonadTraceSTM m where- {-# MINIMAL traceTVar, traceTQueue, traceTBQueue #-}-- -- | Construct a trace output out of previous & new value of a 'TVar'. The- -- callback is called whenever an stm transaction which modifies the 'TVar' is- -- committed.- --- -- This is supported by 'IOSim' (and 'IOSimPOR'); 'IO' has a trivial instance.- --- -- The simplest example is:- --- -- >- -- > traceTVar (Proxy @m) tvar (\_ -> TraceString . show)- -- >- --- -- Note that the interpretation of `TraceValue` depends on the monad `m`- -- itself (see 'TraceValue').- --- traceTVar :: proxy m- -> TVar m a- -> (Maybe a -> a -> InspectMonadSTM m TraceValue)- -- ^ callback which receives initial value or 'Nothing' (if it- -- is a newly created 'TVar'), and the committed value.- -> STM m ()--- traceTMVar :: proxy m- -> TMVar m a- -> (Maybe (Maybe a) -> (Maybe a) -> InspectMonadSTM m TraceValue)- -> STM m ()-- traceTQueue :: proxy m- -> TQueue m a- -> (Maybe [a] -> [a] -> InspectMonadSTM m TraceValue)- -> STM m ()-- traceTBQueue :: proxy m- -> TBQueue m a- -> (Maybe [a] -> [a] -> InspectMonadSTM m TraceValue)- -> STM m ()-- traceTSem :: proxy m- -> TSem m- -> (Maybe Integer -> Integer -> InspectMonadSTM m TraceValue)- -> STM m ()-- default traceTMVar :: TMVar m a ~ TMVarDefault m a- => proxy m- -> TMVar m a- -> (Maybe (Maybe a) -> Maybe a -> InspectMonadSTM m TraceValue)- -> STM m ()- traceTMVar = traceTMVarDefault-- default traceTSem :: TSem m ~ TSemDefault m- => proxy m- -> TSem m- -> (Maybe Integer -> Integer -> InspectMonadSTM m TraceValue)- -> STM m ()- traceTSem = traceTSemDefault--- traceTVarIO :: TVar m a- -> (Maybe a -> a -> InspectMonadSTM m TraceValue)- -> m ()-- traceTMVarIO :: TMVar m a- -> (Maybe (Maybe a) -> Maybe a -> InspectMonadSTM m TraceValue)- -> m ()-- traceTQueueIO :: TQueue m a- -> (Maybe [a] -> [a] -> InspectMonadSTM m TraceValue)- -> m ()-- traceTBQueueIO :: TBQueue m a- -> (Maybe [a] -> [a] -> InspectMonadSTM m TraceValue)- -> m ()-- traceTSemIO :: TSem m- -> (Maybe Integer -> Integer -> InspectMonadSTM m TraceValue)- -> m ()-- default traceTVarIO :: TVar m a- -> (Maybe a -> a -> InspectMonadSTM m TraceValue)- -> m ()- traceTVarIO = \v f -> atomically (traceTVar Proxy v f)-- default traceTMVarIO :: TMVar m a- -> (Maybe (Maybe a) -> (Maybe a) -> InspectMonadSTM m TraceValue)- -> m ()- traceTMVarIO = \v f -> atomically (traceTMVar Proxy v f)-- default traceTQueueIO :: TQueue m a- -> (Maybe [a] -> [a] -> InspectMonadSTM m TraceValue)- -> m ()- traceTQueueIO = \v f -> atomically (traceTQueue Proxy v f)-- default traceTBQueueIO :: TBQueue m a- -> (Maybe [a] -> [a] -> InspectMonadSTM m TraceValue)- -> m ()- traceTBQueueIO = \v f -> atomically (traceTBQueue Proxy v f)-- default traceTSemIO :: TSem m- -> (Maybe Integer -> Integer -> InspectMonadSTM m TraceValue)- -> m ()- traceTSemIO = \v f -> atomically (traceTSem Proxy v f)--debugTraceTVar :: (MonadTraceSTM m, Show a)- => proxy m- -> TVar m a- -> STM m ()-debugTraceTVar p tvar =- traceTVar p tvar (\pv v -> pure $ TraceString $ case (pv, v) of- (Nothing, _) -> error "Unreachable"- (Just st', st'') -> "Modified: " <> show st' <> " -> " <> show st''- )--debugTraceTVarIO :: (MonadTraceSTM m, Show a)- => TVar m a- -> m ()-debugTraceTVarIO tvar =- traceTVarIO tvar (\pv v -> pure $ TraceString $ case (pv, v) of- (Nothing, _) -> error "Unreachable"- (Just st', st'') -> "Modified: " <> show st' <> " -> " <> show st''- )--debugTraceTMVar :: (MonadTraceSTM m, Show a)- => proxy m- -> TMVar m a- -> STM m ()-debugTraceTMVar p tmvar =- traceTMVar p tmvar (\pv v -> pure $ TraceString $ case (pv, v) of- (Nothing, _) -> error "Unreachable"- (Just Nothing, Just st') -> "Put: " <> show st'- (Just Nothing, Nothing) -> "Remains empty"- (Just Just{}, Nothing) -> "Take"- (Just (Just st'), Just st'') -> "Modified: " <> show st' <> " -> " <> show st''- )--debugTraceTMVarIO :: (Show a, MonadTraceSTM m)- => TMVar m a- -> m ()-debugTraceTMVarIO tmvar =- traceTMVarIO tmvar (\pv v -> pure $ TraceString $ case (pv, v) of- (Nothing, _) -> error "Unreachable"- (Just Nothing, Just st') -> "Put: " <> show st'- (Just Nothing, Nothing) -> "Remains empty"- (Just Just{}, Nothing) -> "Take"- (Just (Just st'), Just st'') -> "Modified: " <> show st' <> " -> " <> show st''- )------- Instance for IO uses the existing STM library implementations-----instance MonadSTM IO where- type STM IO = STM.STM-- atomically = wrapBlockedIndefinitely . STM.atomically-- type TVar IO = STM.TVar- type TMVar IO = STM.TMVar- type TQueue IO = STM.TQueue- type TBQueue IO = STM.TBQueue- type TArray IO = STM.TArray- type TSem IO = STM.TSem- type TChan IO = STM.TChan-- newTVar = STM.newTVar- readTVar = STM.readTVar- writeTVar = STM.writeTVar- retry = STM.retry- orElse = STM.orElse- modifyTVar = STM.modifyTVar- modifyTVar' = STM.modifyTVar'- stateTVar = STM.stateTVar- swapTVar = STM.swapTVar- check = STM.check- newTMVar = STM.newTMVar- newEmptyTMVar = STM.newEmptyTMVar- takeTMVar = STM.takeTMVar- tryTakeTMVar = STM.tryTakeTMVar- putTMVar = STM.putTMVar- tryPutTMVar = STM.tryPutTMVar- readTMVar = STM.readTMVar- tryReadTMVar = STM.tryReadTMVar- swapTMVar = STM.swapTMVar-#if MIN_VERSION_stm(2, 5, 1)- writeTMVar = STM.writeTMVar-#else- writeTMVar = writeTMVar'-#endif- isEmptyTMVar = STM.isEmptyTMVar- newTQueue = STM.newTQueue- readTQueue = STM.readTQueue- tryReadTQueue = STM.tryReadTQueue- peekTQueue = STM.peekTQueue- tryPeekTQueue = STM.tryPeekTQueue- flushTQueue = STM.flushTQueue- writeTQueue = STM.writeTQueue- isEmptyTQueue = STM.isEmptyTQueue- unGetTQueue = STM.unGetTQueue- newTBQueue = STM.newTBQueue- readTBQueue = STM.readTBQueue- tryReadTBQueue = STM.tryReadTBQueue- peekTBQueue = STM.peekTBQueue- tryPeekTBQueue = STM.tryPeekTBQueue- writeTBQueue = STM.writeTBQueue- flushTBQueue = STM.flushTBQueue- lengthTBQueue = STM.lengthTBQueue- isEmptyTBQueue = STM.isEmptyTBQueue- isFullTBQueue = STM.isFullTBQueue- unGetTBQueue = STM.unGetTBQueue- newTSem = STM.newTSem- waitTSem = STM.waitTSem- signalTSem = STM.signalTSem- signalTSemN = STM.signalTSemN-- newTChan = STM.newTChan- newBroadcastTChan = STM.newBroadcastTChan- dupTChan = STM.dupTChan- cloneTChan = STM.cloneTChan- readTChan = STM.readTChan- tryReadTChan = STM.tryReadTChan- peekTChan = STM.peekTChan- tryPeekTChan = STM.tryPeekTChan- writeTChan = STM.writeTChan- unGetTChan = STM.unGetTChan- isEmptyTChan = STM.isEmptyTChan-- newTVarIO = STM.newTVarIO- readTVarIO = STM.readTVarIO- newTMVarIO = STM.newTMVarIO- newEmptyTMVarIO = STM.newEmptyTMVarIO- newTQueueIO = STM.newTQueueIO- newTBQueueIO = STM.newTBQueueIO- newTChanIO = STM.newTChanIO- newBroadcastTChanIO = STM.newBroadcastTChanIO---- | noop instance----instance MonadLabelledSTM IO where- labelTVar = \_ _ -> return ()- labelTMVar = \_ _ -> return ()- labelTQueue = \_ _ -> return ()- labelTBQueue = \_ _ -> return ()- labelTArray = \_ _ -> return ()- labelTSem = \_ _ -> return ()- labelTChan = \_ _ -> return ()-- labelTVarIO = \_ _ -> return ()- labelTMVarIO = \_ _ -> return ()- labelTQueueIO = \_ _ -> return ()- labelTBQueueIO = \_ _ -> return ()- labelTArrayIO = \_ _ -> return ()- labelTSemIO = \_ _ -> return ()- labelTChanIO = \_ _ -> return ()---- | noop instance----instance MonadTraceSTM IO where- traceTVar = \_ _ _ -> return ()- traceTMVar = \_ _ _ -> return ()- traceTQueue = \_ _ _ -> return ()- traceTBQueue = \_ _ _ -> return ()- traceTSem = \_ _ _ -> return ()-- traceTVarIO = \_ _ -> return ()- traceTMVarIO = \_ _ -> return ()- traceTQueueIO = \_ _ -> return ()- traceTBQueueIO = \_ _ -> return ()- traceTSemIO = \_ _ -> return ()---- | Wrapper around 'BlockedIndefinitelyOnSTM' that stores a call stack-data BlockedIndefinitely = BlockedIndefinitely {- blockedIndefinitelyCallStack :: CallStack- , blockedIndefinitelyException :: BlockedIndefinitelyOnSTM- }- deriving Show--instance Exception BlockedIndefinitely where- displayException (BlockedIndefinitely cs e) = unlines [- displayException e- , prettyCallStack cs- ]--wrapBlockedIndefinitely :: HasCallStack => IO a -> IO a-wrapBlockedIndefinitely = handle (throwIO . BlockedIndefinitely callStack)------- Default TMVar implementation in terms of TVars-----newtype TMVarDefault m a = TMVar (TVar m (Maybe a))--labelTMVarDefault- :: MonadLabelledSTM m- => TMVarDefault m a -> String -> STM m ()-labelTMVarDefault (TMVar tvar) = labelTVar tvar--traceTMVarDefault- :: MonadTraceSTM m- => proxy m- -> TMVarDefault m a- -> (Maybe (Maybe a) -> Maybe a -> InspectMonadSTM m TraceValue)- -> STM m ()-traceTMVarDefault p (TMVar t) f = traceTVar p t f--newTMVarDefault :: MonadSTM m => a -> STM m (TMVarDefault m a)-newTMVarDefault a = do- t <- newTVar (Just a)- return (TMVar t)--newEmptyTMVarDefault :: MonadSTM m => STM m (TMVarDefault m a)-newEmptyTMVarDefault = do- t <- newTVar Nothing- return (TMVar t)--takeTMVarDefault :: MonadSTM m => TMVarDefault m a -> STM m a-takeTMVarDefault (TMVar t) = do- m <- readTVar t- case m of- Nothing -> retry- Just a -> do writeTVar t Nothing; return a--tryTakeTMVarDefault :: MonadSTM m => TMVarDefault m a -> STM m (Maybe a)-tryTakeTMVarDefault (TMVar t) = do- m <- readTVar t- case m of- Nothing -> return Nothing- Just a -> do writeTVar t Nothing; return (Just a)--putTMVarDefault :: MonadSTM m => TMVarDefault m a -> a -> STM m ()-putTMVarDefault (TMVar t) a = do- m <- readTVar t- case m of- Nothing -> do writeTVar t (Just a); return ()- Just _ -> retry--tryPutTMVarDefault :: MonadSTM m => TMVarDefault m a -> a -> STM m Bool-tryPutTMVarDefault (TMVar t) a = do- m <- readTVar t- case m of- Nothing -> do writeTVar t (Just a); return True- Just _ -> return False--readTMVarDefault :: MonadSTM m => TMVarDefault m a -> STM m a-readTMVarDefault (TMVar t) = do- m <- readTVar t- case m of- Nothing -> retry- Just a -> return a--tryReadTMVarDefault :: MonadSTM m => TMVarDefault m a -> STM m (Maybe a)-tryReadTMVarDefault (TMVar t) = readTVar t--swapTMVarDefault :: MonadSTM m => TMVarDefault m a -> a -> STM m a-swapTMVarDefault (TMVar t) new = do- m <- readTVar t- case m of- Nothing -> retry- Just old -> do writeTVar t (Just new); return old--writeTMVarDefault :: MonadSTM m => TMVarDefault m a -> a -> STM m ()-writeTMVarDefault (TMVar t) new = writeTVar t (Just new)--isEmptyTMVarDefault :: MonadSTM m => TMVarDefault m a -> STM m Bool-isEmptyTMVarDefault (TMVar t) = do- m <- readTVar t- case m of- Nothing -> return True- Just _ -> return False------- Default TQueue implementation in terms of TVars (used by sim)-----data TQueueDefault m a = TQueue !(TVar m [a])- !(TVar m [a])--labelTQueueDefault- :: MonadLabelledSTM m- => TQueueDefault m a -> String -> STM m ()-labelTQueueDefault (TQueue read write) label = do- labelTVar read (label ++ "-read")- labelTVar write (label ++ "-write")--newTQueueDefault :: MonadSTM m => STM m (TQueueDefault m a)-newTQueueDefault = do- read <- newTVar []- write <- newTVar []- return (TQueue read write)--writeTQueueDefault :: MonadSTM m => TQueueDefault m a -> a -> STM m ()-writeTQueueDefault (TQueue _read write) a = do- listend <- readTVar write- writeTVar write (a:listend)--readTQueueDefault :: MonadSTM m => TQueueDefault m a -> STM m a-readTQueueDefault queue = maybe retry return =<< tryReadTQueueDefault queue--tryReadTQueueDefault :: MonadSTM m => TQueueDefault m a -> STM m (Maybe a)-tryReadTQueueDefault (TQueue read write) = do- xs <- readTVar read- case xs of- (x:xs') -> do- writeTVar read xs'- return (Just x)- [] -> do- ys <- readTVar write- case reverse ys of- [] -> return Nothing- (z:zs) -> do- writeTVar write []- writeTVar read zs- return (Just z)--isEmptyTQueueDefault :: MonadSTM m => TQueueDefault m a -> STM m Bool-isEmptyTQueueDefault (TQueue read write) = do- xs <- readTVar read- case xs of- (_:_) -> return False- [] -> do ys <- readTVar write- case ys of- [] -> return True- _ -> return False--peekTQueueDefault :: MonadSTM m => TQueueDefault m a -> STM m a-peekTQueueDefault (TQueue read _write) = do- xs <- readTVar read- case xs of- (x:_) -> return x- _ -> retry--tryPeekTQueueDefault :: MonadSTM m => TQueueDefault m a -> STM m (Maybe a)-tryPeekTQueueDefault (TQueue read _write) = do- xs <- readTVar read- case xs of- (x:_) -> return (Just x)- _ -> return Nothing---flushTQueueDefault :: MonadSTM m => TQueueDefault m a -> STM m [a]-flushTQueueDefault (TQueue read write) = do- xs <- readTVar read- ys <- readTVar write- unless (null xs) $ writeTVar read []- unless (null ys) $ writeTVar write []- return (xs ++ reverse ys)--unGetTQueueDefault :: MonadSTM m => TQueueDefault m a -> a -> STM m ()-unGetTQueueDefault (TQueue read _write) a = modifyTVar read (a:)--------- Default TBQueue implementation in terms of TVars-----data TBQueueDefault m a = TBQueue- !(TVar m Natural) -- read capacity- !(TVar m [a]) -- elements waiting for read- !(TVar m Natural) -- write capacity- !(TVar m [a]) -- written elements- !Natural--labelTBQueueDefault- :: MonadLabelledSTM m- => TBQueueDefault m a -> String -> STM m ()-labelTBQueueDefault (TBQueue rsize read wsize write _size) label = do- labelTVar rsize (label ++ "-rsize")- labelTVar read (label ++ "-read")- labelTVar wsize (label ++ "-wsize")- labelTVar write (label ++ "-write")--newTBQueueDefault :: MonadSTM m => Natural -> STM m (TBQueueDefault m a)-newTBQueueDefault size = do- rsize <- newTVar 0- read <- newTVar []- wsize <- newTVar size- write <- newTVar []- return (TBQueue rsize read wsize write size)--readTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m a-readTBQueueDefault queue = maybe retry return =<< tryReadTBQueueDefault queue--tryReadTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m (Maybe a)-tryReadTBQueueDefault (TBQueue rsize read _wsize write _size) = do- xs <- readTVar read- r <- readTVar rsize- writeTVar rsize $! r + 1- case xs of- (x:xs') -> do- writeTVar read xs'- return (Just x)- [] -> do- ys <- readTVar write- case reverse ys of- [] -> return Nothing-- -- NB. lazy: we want the transaction to be- -- short, otherwise it will conflict- (z:zs) -> do- writeTVar write []- writeTVar read zs- return (Just z)--peekTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m a-peekTBQueueDefault (TBQueue _rsize read _wsize _write _size) = do- xs <- readTVar read- case xs of- (x:_) -> return x- _ -> retry--tryPeekTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m (Maybe a)-tryPeekTBQueueDefault (TBQueue _rsize read _wsize _write _size) = do- xs <- readTVar read- case xs of- (x:_) -> return (Just x)- _ -> return Nothing--writeTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> a -> STM m ()-writeTBQueueDefault (TBQueue rsize _read wsize write _size) a = do- w <- readTVar wsize- if (w > 0)- then do writeTVar wsize $! w - 1- else do- r <- readTVar rsize- if (r > 0)- then do writeTVar rsize 0- writeTVar wsize $! r - 1- else retry- listend <- readTVar write- writeTVar write (a:listend)--isEmptyTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m Bool-isEmptyTBQueueDefault (TBQueue _rsize read _wsize write _size) = do- xs <- readTVar read- case xs of- (_:_) -> return False- [] -> do ys <- readTVar write- case ys of- [] -> return True- _ -> return False--isFullTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m Bool-isFullTBQueueDefault (TBQueue rsize _read wsize _write _size) = do- w <- readTVar wsize- if (w > 0)- then return False- else do- r <- readTVar rsize- if (r > 0)- then return False- else return True--lengthTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m Natural-lengthTBQueueDefault (TBQueue rsize _read wsize _write size) = do- r <- readTVar rsize- w <- readTVar wsize- return $! size - r - w---flushTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> STM m [a]-flushTBQueueDefault (TBQueue rsize read wsize write size) = do- xs <- readTVar read- ys <- readTVar write- if null xs && null ys- then return []- else do- writeTVar read []- writeTVar write []- writeTVar rsize 0- writeTVar wsize size- return (xs ++ reverse ys)--unGetTBQueueDefault :: MonadSTM m => TBQueueDefault m a -> a -> STM m ()-unGetTBQueueDefault (TBQueue rsize read wsize _write _size) a = do- r <- readTVar rsize- if (r > 0)- then do writeTVar rsize $! r - 1- else do- w <- readTVar wsize- if (w > 0)- then writeTVar wsize $! w - 1- else retry- xs <- readTVar read- writeTVar read (a:xs)-------- Default `TArray` implementation------- | Default implementation of 'TArray'.----data TArrayDefault m i e = TArray (Array i (TVar m e))--deriving instance (Eq (TVar m e), Ix i) => Eq (TArrayDefault m i e)--instance (Monad stm, MonadSTM m, stm ~ STM m)- => MArray (TArrayDefault m) e stm where- getBounds (TArray a) = return (bounds a)- newArray b e = do- a <- rep (rangeSize b) (newTVar e)- return $ TArray (listArray b a)- newArray_ b = do- a <- rep (rangeSize b) (newTVar arrEleBottom)- return $ TArray (listArray b a)- unsafeRead (TArray a) i = readTVar $ unsafeAt a i- unsafeWrite (TArray a) i e = writeTVar (unsafeAt a i) e- getNumElements (TArray a) = return (numElements a)--rep :: Monad m => Int -> m a -> m [a]-rep n m = go n []- where- go 0 xs = return xs- go i xs = do- x <- m- go (i-1) (x:xs)--labelTArrayDefault :: ( MonadLabelledSTM m- , Ix i- , Show i- )- => TArrayDefault m i e -> String -> STM m ()-labelTArrayDefault (TArray arr) name = do- let as = Array.assocs arr- traverse_ (\(i, v) -> labelTVar v (name ++ ":" ++ show i)) as-------- Default `TSem` implementation-----newtype TSemDefault m = TSem (TVar m Integer)--labelTSemDefault :: MonadLabelledSTM m => TSemDefault m -> String -> STM m ()-labelTSemDefault (TSem t) = labelTVar t--traceTSemDefault :: MonadTraceSTM m- => proxy m- -> TSemDefault m- -> (Maybe Integer -> Integer -> InspectMonadSTM m TraceValue)- -> STM m ()-traceTSemDefault proxy (TSem t) k = traceTVar proxy t k--newTSemDefault :: MonadSTM m => Integer -> STM m (TSemDefault m)-newTSemDefault i = TSem <$> (newTVar $! i)--waitTSemDefault :: MonadSTM m => TSemDefault m -> STM m ()-waitTSemDefault (TSem t) = do- i <- readTVar t- when (i <= 0) retry- writeTVar t $! (i-1)--signalTSemDefault :: MonadSTM m => TSemDefault m -> STM m ()-signalTSemDefault (TSem t) = do- i <- readTVar t- writeTVar t $! i+1--signalTSemNDefault :: MonadSTM m => Natural -> TSemDefault m -> STM m ()-signalTSemNDefault 0 _ = return ()-signalTSemNDefault 1 s = signalTSemDefault s-signalTSemNDefault n (TSem t) = do- i <- readTVar t- writeTVar t $! i+(toInteger n)------- Default `TChan` implementation-----type TVarList m a = TVar m (TList m a)-data TList m a = TNil | TCons a (TVarList m a)--data TChanDefault m a = TChan (TVar m (TVarList m a)) (TVar m (TVarList m a))--labelTChanDefault :: MonadLabelledSTM m => TChanDefault m a -> String -> STM m ()-labelTChanDefault (TChan read write) name = do- labelTVar read (name ++ ":read")- labelTVar write (name ++ ":write")--newTChanDefault :: MonadSTM m => STM m (TChanDefault m a)-newTChanDefault = do- hole <- newTVar TNil- read <- newTVar hole- write <- newTVar hole- return (TChan read write)--newBroadcastTChanDefault :: MonadSTM m => STM m (TChanDefault m a)-newBroadcastTChanDefault = do- write_hole <- newTVar TNil- read <- newTVar (error "reading from a TChan created by newBroadcastTChan; use dupTChan first")- write <- newTVar write_hole- return (TChan read write)--writeTChanDefault :: MonadSTM m => TChanDefault m a -> a -> STM m ()-writeTChanDefault (TChan _read write) a = do- listend <- readTVar write -- listend == TVar pointing to TNil- new_listend <- newTVar TNil- writeTVar listend (TCons a new_listend)- writeTVar write new_listend--readTChanDefault :: MonadSTM m => TChanDefault m a -> STM m a-readTChanDefault (TChan read _write) = do- listhead <- readTVar read- head_ <- readTVar listhead- case head_ of- TNil -> retry- TCons a tail_ -> do- writeTVar read tail_- return a--tryReadTChanDefault :: MonadSTM m => TChanDefault m a -> STM m (Maybe a)-tryReadTChanDefault (TChan read _write) = do- listhead <- readTVar read- head_ <- readTVar listhead- case head_ of- TNil -> return Nothing- TCons a tl -> do- writeTVar read tl- return (Just a)--peekTChanDefault :: MonadSTM m => TChanDefault m a -> STM m a-peekTChanDefault (TChan read _write) = do- listhead <- readTVar read- head_ <- readTVar listhead- case head_ of- TNil -> retry- TCons a _ -> return a--tryPeekTChanDefault :: MonadSTM m => TChanDefault m a -> STM m (Maybe a)-tryPeekTChanDefault (TChan read _write) = do- listhead <- readTVar read- head_ <- readTVar listhead- case head_ of- TNil -> return Nothing- TCons a _ -> return (Just a)--dupTChanDefault :: MonadSTM m => TChanDefault m a -> STM m (TChanDefault m a)-dupTChanDefault (TChan _read write) = do- hole <- readTVar write- new_read <- newTVar hole- return (TChan new_read write)--unGetTChanDefault :: MonadSTM m => TChanDefault m a -> a -> STM m ()-unGetTChanDefault (TChan read _write) a = do- listhead <- readTVar read- newhead <- newTVar (TCons a listhead)- writeTVar read newhead--isEmptyTChanDefault :: MonadSTM m => TChanDefault m a -> STM m Bool-isEmptyTChanDefault (TChan read _write) = do- listhead <- readTVar read- head_ <- readTVar listhead- case head_ of- TNil -> return True- TCons _ _ -> return False--cloneTChanDefault :: MonadSTM m => TChanDefault m a -> STM m (TChanDefault m a)-cloneTChanDefault (TChan read write) = do- readpos <- readTVar read- new_read <- newTVar readpos- return (TChan new_read write)----- | 'throwIO' specialised to @stm@ monad.----throwSTM :: (MonadSTM m, MonadThrow.MonadThrow (STM m), Exception e)- => e -> STM m a-throwSTM = MonadThrow.throwIO----- | 'catch' specialized for an @stm@ monad.----catchSTM :: (MonadSTM m, MonadThrow.MonadCatch (STM m), Exception e)- => STM m a -> (e -> STM m a) -> STM m a-catchSTM = MonadThrow.catch------- ReaderT instance-------- | The underlying stm monad is also transformed.----instance MonadSTM m => MonadSTM (ReaderT r m) where- type STM (ReaderT r m) = ReaderT r (STM m)- atomically (ReaderT stm) = ReaderT $ \r -> atomically (stm r)-- type TVar (ReaderT r m) = TVar m- newTVar = lift . newTVar- readTVar = lift . readTVar- writeTVar = lift .: writeTVar- retry = lift retry- orElse (ReaderT a) (ReaderT b) = ReaderT $ \r -> a r `orElse` b r-- modifyTVar = lift .: modifyTVar- modifyTVar' = lift .: modifyTVar'- stateTVar = lift .: stateTVar- swapTVar = lift .: swapTVar- check = lift . check-- type TMVar (ReaderT r m) = TMVar m- newTMVar = lift . newTMVar- newEmptyTMVar = lift newEmptyTMVar- takeTMVar = lift . takeTMVar- tryTakeTMVar = lift . tryTakeTMVar- putTMVar = lift .: putTMVar- tryPutTMVar = lift .: tryPutTMVar- readTMVar = lift . readTMVar- tryReadTMVar = lift . tryReadTMVar- swapTMVar = lift .: swapTMVar- writeTMVar = lift .: writeTMVar- isEmptyTMVar = lift . isEmptyTMVar-- type TQueue (ReaderT r m) = TQueue m- newTQueue = lift newTQueue- readTQueue = lift . readTQueue- tryReadTQueue = lift . tryReadTQueue- peekTQueue = lift . peekTQueue- tryPeekTQueue = lift . tryPeekTQueue- flushTQueue = lift . flushTQueue- writeTQueue v = lift . writeTQueue v- isEmptyTQueue = lift . isEmptyTQueue- unGetTQueue = lift .: unGetTQueue-- type TBQueue (ReaderT r m) = TBQueue m- newTBQueue = lift . newTBQueue- readTBQueue = lift . readTBQueue- tryReadTBQueue = lift . tryReadTBQueue- peekTBQueue = lift . peekTBQueue- tryPeekTBQueue = lift . tryPeekTBQueue- flushTBQueue = lift . flushTBQueue- writeTBQueue = lift .: writeTBQueue- lengthTBQueue = lift . lengthTBQueue- isEmptyTBQueue = lift . isEmptyTBQueue- isFullTBQueue = lift . isFullTBQueue- unGetTBQueue = lift .: unGetTBQueue-- type TArray (ReaderT r m) = TArray m-- type TSem (ReaderT r m) = TSem m- newTSem = lift . newTSem- waitTSem = lift . waitTSem- signalTSem = lift . signalTSem- signalTSemN = lift .: signalTSemN-- type TChan (ReaderT r m) = TChan m- newTChan = lift newTChan- newBroadcastTChan = lift newBroadcastTChan- dupTChan = lift . dupTChan- cloneTChan = lift . cloneTChan- readTChan = lift . readTChan- tryReadTChan = lift . tryReadTChan- peekTChan = lift . peekTChan- tryPeekTChan = lift . tryPeekTChan- writeTChan = lift .: writeTChan- unGetTChan = lift .: unGetTChan- isEmptyTChan = lift . isEmptyTChan--instance MonadInspectSTM m => MonadInspectSTM (ReaderT r m) where- type InspectMonadSTM (ReaderT r m) = InspectMonadSTM m- inspectTVar _ = inspectTVar (Proxy :: Proxy m)- inspectTMVar _ = inspectTMVar (Proxy :: Proxy m)--instance MonadTraceSTM m => MonadTraceSTM (ReaderT r m) where- traceTVar _ = lift .: traceTVar Proxy- traceTMVar _ = lift .: traceTMVar Proxy- traceTQueue _ = lift .: traceTQueue Proxy- traceTBQueue _ = lift .: traceTBQueue Proxy- traceTSem _ = lift .: traceTSem Proxy--(.:) :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)-(f .: g) x y = f (g x y)---- TODO: writeTMVar was introduced in stm-2.5.1. But io-sim supports stm older than that--- Therefore this can be removed once we don't need backwards compatibility with stm.-#if !MIN_VERSION_stm(2,5,1)-writeTMVar' :: STM.TMVar a -> a -> STM.STM ()-writeTMVar' t new = STM.tryTakeTMVar t >> STM.putTMVar t new-#endif
− src/Control/Monad/Class/MonadSay.hs
@@ -1,13 +0,0 @@-module Control.Monad.Class.MonadSay where--import Control.Monad.Reader-import Data.ByteString.Char8 qualified as BSC--class Monad m => MonadSay m where- say :: String -> m ()--instance MonadSay IO where- say = BSC.putStrLn . BSC.pack--instance MonadSay m => MonadSay (ReaderT r m) where- say = lift . say
− src/Control/Monad/Class/MonadTest.hs
@@ -1,17 +0,0 @@-module Control.Monad.Class.MonadTest (MonadTest (..)) where--import Control.Monad.Reader---- | A helper monad for /IOSimPOR/.-class Monad m => MonadTest m where- -- | Mark a thread for schedule exploration. All threads that are forked by- -- it are also included in the exploration.- --- exploreRaces :: m ()- exploreRaces = return ()--instance MonadTest IO--instance MonadTest m => MonadTest (ReaderT e m) where- exploreRaces = lift exploreRaces-
− src/Control/Monad/Class/MonadThrow.hs
@@ -1,328 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE TypeFamilies #-}---- | A generalisation of--- <https://hackage.haskell.org/package/base/docs/Control-Exception.html Control.Exception>--- API to both 'IO' and <https://hackage.haskell.org/package/io-sim IOSim>.----module Control.Monad.Class.MonadThrow- ( MonadThrow (..)- , MonadCatch (..)- , MonadMask (..)- , MonadMaskingState- , MonadEvaluate (..)- , MaskingState (..)- , Exception (..)- , SomeException- , ExitCase (..)- , Handler (..)- , catches- ) where--import Control.Exception (Exception (..), MaskingState, SomeException)-import Control.Exception qualified as IO-import Control.Monad (liftM)--import Control.Monad.Reader (ReaderT (..), lift, runReaderT)--import Control.Monad.STM (STM)-import Control.Monad.STM qualified as STM--#if __GLASGOW_HASKELL__ >= 910-import GHC.Internal.Exception.Context (ExceptionAnnotation)-#endif---- | Throwing exceptions, and resource handling in the presence of exceptions.------ Does not include the ability to respond to exceptions.----class Monad m => MonadThrow m where--#if __GLASGOW_HASKELL__ >= 910- {-# MINIMAL throwIO, annotateIO #-}-#else- {-# MINIMAL throwIO #-}-#endif-- throwIO :: Exception e => e -> m a-- bracket :: m a -> (a -> m b) -> (a -> m c) -> m c- bracket_ :: m a -> m b -> m c -> m c- finally :: m a -> m b -> m a-#if __GLASGOW_HASKELL__ >= 910- -- | See 'IO.annotateIO'.- --- -- @since 1.5.0.0- annotateIO :: forall e a. ExceptionAnnotation e => e -> m a -> m a-#endif-- default bracket :: MonadCatch m => m a -> (a -> m b) -> (a -> m c) -> m c-- bracket before after =- liftM fst .- generalBracket- before- (\a _exitCase -> after a)-- bracket_ before after thing = bracket before (const after) (const thing)-- a `finally` sequel =- bracket_ (return ()) sequel a---- | Catching exceptions.------ Covers standard utilities to respond to exceptions.----class MonadThrow m => MonadCatch m where-- {-# MINIMAL catch #-}-- catch :: Exception e => m a -> (e -> m a) -> m a- catchJust :: Exception e => (e -> Maybe b) -> m a -> (b -> m a) -> m a-- try :: Exception e => m a -> m (Either e a)- tryJust :: Exception e => (e -> Maybe b) -> m a -> m (Either b a)-- handle :: Exception e => (e -> m a) -> m a -> m a- handleJust :: Exception e => (e -> Maybe b) -> (b -> m a) -> m a -> m a-- onException :: m a -> m b -> m a- bracketOnError :: m a -> (a -> m b) -> (a -> m c) -> m c-- -- | General form of bracket- --- -- See <http://hackage.haskell.org/package/exceptions-0.10.0/docs/Control-Monad-Catch.html#v:generalBracket>- -- for discussion and motivation.- generalBracket :: m a -> (a -> ExitCase b -> m c) -> (a -> m b) -> m (b, c)-- default generalBracket- :: MonadMask m- => m a -> (a -> ExitCase b -> m c) -> (a -> m b) -> m (b, c)-- catchJust p a handler =- catch a handler'- where- handler' e = case p e of- Nothing -> throwIO e- Just b -> handler b-- try a = catch (Right `fmap` a) (return . Left)-- tryJust p a = do- r <- try a- case r of- Right v -> return (Right v)- Left e -> case p e of- Nothing -> throwIO e- Just b -> return (Left b)-- handle = flip catch- handleJust p = flip (catchJust p)-- onException action what =- action `catch` \e -> do- _ <- what- throwIO (e :: SomeException)-- bracketOnError acquire release = liftM fst . generalBracket- acquire- (\a exitCase -> case exitCase of- ExitCaseSuccess _ -> return ()- _ -> do- _ <- release a- return ())-- generalBracket acquire release use =- mask $ \unmasked -> do- resource <- acquire- b <- unmasked (use resource) `catch` \e -> do- _ <- release resource (ExitCaseException e)- throwIO e- c <- release resource (ExitCaseSuccess b)- return (b, c)----- | The default handler type for 'catches', whcih is a generalisation of--- 'IO.Handler'.----data Handler m a = forall e. Exception e => Handler (e -> m a)--deriving instance (Functor m) => Functor (Handler m)---- | Like 'catches' but for 'MonadCatch' rather than only 'IO'.----catches :: forall m a. MonadCatch m- => m a -> [Handler m a] -> m a-catches ma handlers = ma `catch` catchesHandler handlers-{-# SPECIALISE catches :: IO a -> [Handler IO a] -> IO a #-}---- | Used in the default 'catches' implementation.----catchesHandler :: MonadCatch m- => [Handler m a]- -> SomeException- -> m a-catchesHandler handlers e = foldr tryHandler (throwIO e) handlers- where tryHandler (Handler handler) res- = case fromException e of- Just e' -> handler e'- Nothing -> res-{-# SPECIALISE catchesHandler :: [Handler IO a] -> SomeException -> IO a #-}----- | Used in 'generalBracket'------ See @exceptions@ package for discussion and motivation.-data ExitCase a- = ExitCaseSuccess a- | ExitCaseException SomeException- | ExitCaseAbort- deriving (Show, Functor)---- | Support for safely working in the presence of asynchronous exceptions.------ This is typically not needed directly as the utilities in 'MonadThrow' and--- 'MonadCatch' cover most use cases.----class MonadCatch m => MonadMask m where-- {-# MINIMAL mask,- uninterruptibleMask,- getMaskingState,- interruptible #-}-- mask, uninterruptibleMask :: ((forall a. m a -> m a) -> m b) -> m b-- mask_, uninterruptibleMask_ :: m a -> m a- mask_ action = mask $ \_ -> action- uninterruptibleMask_ action = uninterruptibleMask $ \_ -> action-- getMaskingState :: m MaskingState- interruptible :: m a -> m a-- allowInterrupt :: m ()- allowInterrupt = interruptible (return ())--class MonadMask m => MonadMaskingState m-{-# DEPRECATED MonadMaskingState "Use MonadMask instead" #-}----- | Monads which can 'evaluate'.----class MonadEvaluate m where- evaluate :: a -> m a------- Instance for IO uses the existing base library implementations-----instance MonadThrow IO where-- throwIO = IO.throwIO-- bracket = IO.bracket- bracket_ = IO.bracket_- finally = IO.finally-#if __GLASGOW_HASKELL__ >= 910- annotateIO = IO.annotateIO-#endif---instance MonadCatch IO where-- catch = IO.catch-- catchJust = IO.catchJust- try = IO.try- tryJust = IO.tryJust- handle = IO.handle- handleJust = IO.handleJust- onException = IO.onException- bracketOnError = IO.bracketOnError- -- use default implementation of 'generalBracket' (base does not define one)---instance MonadMask IO where-- mask = IO.mask- mask_ = IO.mask_-- uninterruptibleMask = IO.uninterruptibleMask- uninterruptibleMask_ = IO.uninterruptibleMask_-- getMaskingState = IO.getMaskingState- interruptible = IO.interruptible- allowInterrupt = IO.allowInterrupt--instance MonadMaskingState IO--instance MonadEvaluate IO where- evaluate = IO.evaluate------- Instance for STM uses STM primitives and default implementations-----instance MonadThrow STM where- throwIO = STM.throwSTM-#if __GLASGOW_HASKELL__ >= 910- annotateIO ann io = io `catch` \e -> throwIO (IO.addExceptionContext ann e)-#endif--instance MonadCatch STM where- catch = STM.catchSTM-- generalBracket acquire release use = do- resource <- acquire- b <- use resource `catch` \e -> do- _ <- release resource (ExitCaseException e)- throwIO e- c <- release resource (ExitCaseSuccess b)- return (b, c)-------- ReaderT instances-----instance MonadThrow m => MonadThrow (ReaderT r m) where- throwIO = lift . throwIO- bracket acquire release use = ReaderT $ \env ->- bracket- ( runReaderT acquire env)- (\a -> runReaderT (release a) env)- (\a -> runReaderT (use a) env)-#if __GLASGOW_HASKELL__ >= 910- annotateIO ann io = ReaderT $ \env ->- annotateIO ann (runReaderT io env)-#endif--instance MonadCatch m => MonadCatch (ReaderT r m) where- catch act handler = ReaderT $ \env ->- catch- ( runReaderT act env)- (\e -> runReaderT (handler e) env)-- generalBracket acquire release use = ReaderT $ \env ->- generalBracket- ( runReaderT acquire env)- (\a e -> runReaderT (release a e) env)- (\a -> runReaderT (use a) env)--instance MonadMask m => MonadMask (ReaderT r m) where- mask a = ReaderT $ \e -> mask $ \u -> runReaderT (a $ q u) e- where q :: (m a -> m a) -> ReaderT e m a -> ReaderT e m a- q u (ReaderT b) = ReaderT (u . b)- uninterruptibleMask a =- ReaderT $ \e -> uninterruptibleMask $ \u -> runReaderT (a $ q u) e- where q :: (m a -> m a) -> ReaderT e m a -> ReaderT e m a- q u (ReaderT b) = ReaderT (u . b)-- getMaskingState = lift getMaskingState- interruptible a =- ReaderT $ \e -> interruptible (runReaderT a e)- allowInterrupt = lift allowInterrupt--instance (Monad m, MonadEvaluate m) => MonadEvaluate (ReaderT r m) where- evaluate = lift . evaluate
− src/Control/Monad/Class/MonadTime.hs
@@ -1,55 +0,0 @@--- | <https://hackage.haskell.org/package/time time> and--- <https://hackage.haskell.org/package/base base> time API compatible with both--- 'IO' and <https://hackage.haskell.org/package/io-sim IOSim>.----module Control.Monad.Class.MonadTime- ( MonadTime (..)- , MonadMonotonicTimeNSec (..)- -- * 'NominalTime' and its action on 'UTCTime'- , UTCTime- , diffUTCTime- , addUTCTime- , NominalDiffTime- ) where--import Control.Monad.Reader--import Data.Time.Clock (NominalDiffTime, UTCTime, addUTCTime, diffUTCTime)-import Data.Time.Clock qualified as Time-import Data.Word (Word64)-import GHC.Clock qualified as IO (getMonotonicTimeNSec)---class Monad m => MonadMonotonicTimeNSec m where- -- | Time in a monotonic clock, with high precision. The epoch for this- -- clock is arbitrary and does not correspond to any wall clock or calendar.- --- -- The time is measured in nano seconds as does `getMonotonicTimeNSec` from- -- "base".- --- getMonotonicTimeNSec :: m Word64--class Monad m => MonadTime m where- -- | Wall clock time.- --- getCurrentTime :: m UTCTime------- Instances for IO-----instance MonadMonotonicTimeNSec IO where- getMonotonicTimeNSec = IO.getMonotonicTimeNSec--instance MonadTime IO where- getCurrentTime = Time.getCurrentTime------- MTL instances-----instance MonadMonotonicTimeNSec m => MonadMonotonicTimeNSec (ReaderT r m) where- getMonotonicTimeNSec = lift getMonotonicTimeNSec--instance MonadTime m => MonadTime (ReaderT r m) where- getCurrentTime = lift getCurrentTime
− src/Control/Monad/Class/MonadTimer.hs
@@ -1,62 +0,0 @@-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE TypeFamilies #-}---- | Provides classes to handle delays and timeouts which generalised--- <https://hackage.haskell.org/package/base base> API to both 'IO' and--- <https://hackage.haskell.org/package/io-sim IOSim>.----module Control.Monad.Class.MonadTimer- ( MonadDelay (..)- , MonadTimer (..)- ) where--import Control.Concurrent qualified as IO-import Control.Concurrent.Class.MonadSTM-import Control.Concurrent.STM.TVar qualified as STM--import Control.Monad.Reader (ReaderT (..))-import Control.Monad.Trans (lift)--import System.Timeout qualified as IO---- | A typeclass to delay current thread.-class Monad m => MonadDelay m where-- -- | Suspends the current thread for a given number of microseconds- -- (GHC only).- --- -- See `IO.threadDelay`.- threadDelay :: Int -> m ()---- | A typeclass providing utilities for /timeouts/.-class (MonadDelay m, MonadSTM m) => MonadTimer m where-- -- | See `STM.registerDelay`.- registerDelay :: Int -> m (TVar m Bool)-- -- | See `IO.timeout`.- timeout :: Int -> m a -> m (Maybe a)------- Instances for IO-----instance MonadDelay IO where- threadDelay = IO.threadDelay---instance MonadTimer IO where-- registerDelay = STM.registerDelay- timeout = IO.timeout------- Transformer's instances-----instance MonadDelay m => MonadDelay (ReaderT r m) where- threadDelay = lift . threadDelay--instance MonadTimer m => MonadTimer (ReaderT r m) where- registerDelay = lift . registerDelay- timeout d f = ReaderT $ \r -> timeout d (runReaderT f r)