HORIZON HASKELLDocslts/ghc-9.10.xc74966e2026-09-27Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · c74966e · 2026-09-27

Moduleeffectful-2.3.0.0Haskell2010

Effectful.Concurrent.STM

  • 7 types
  • 65 values

Effect

1 declaration
datadata Concurrent (a :: Type -> Type) b
#

Provide the ability to run Eff computations concurrently in multiple threads and communicate between them.

Warning: unless you stick to high level functions from the withAsync family, the Concurrent effect makes it possible to escape the scope of any scoped effect operation. Consider the following:

Example1 expression
import qualified Effectful.Reader.Static as R
Example1 expression
printAsk msg = liftIO . putStrLn . (msg ++) . (": " ++) =<< R.ask
Example1 expression
:{  runEff . R.runReader "GLOBAL" . runConcurrent $ do    a <- R.local (const "LOCAL") $ do      a <- async $ do        printAsk "child (first)"        threadDelay 20000        printAsk "child (second)"      threadDelay 10000      printAsk "parent (inside)"      pure a    printAsk "parent (outside)"    wait a:}child (first): LOCALparent (inside): LOCALparent (outside): GLOBALchild (second): LOCAL

Note that the asynchronous computation doesn't respect the scope of local, i.e. the child thread still behaves like it's inside the local block, even though the parent thread already got out of it.

This is because the value provided by the Reader effect is thread local, i.e. each thread manages its own version of it. For the Reader it is the only reasonable behavior, it wouldn't be very useful if its "read only" value was affected by calls to local from its parent or child threads.

However, the cut isn't so clear if it comes to effects that provide access to a mutable state. That's why statically dispatched State and Writer effects come in two flavors, local and shared:

Example2 expressions
import qualified Effectful.State.Static.Local as SL:{  runEff . SL.execState "Hi" . runConcurrent $ do    replicateConcurrently_ 3 $ SL.modify (++ "!"):}"Hi"
Example2 expressions
import qualified Effectful.State.Static.Shared as SS:{  runEff . SS.execState "Hi" . runConcurrent $ do    replicateConcurrently_ 3 $ SS.modify (++ "!"):}"Hi!!!"

In the first example state updates made concurrently are not reflected in the parent thread because the value is thread local, but in the second example they are, because the value is shared.

Instances2DispatchOf, StaticRep

Handlers

Core

7 declarations
newtypenewtype STM a
#

A monad supporting atomic memory transactions.

Instances14Monad, Functor, MonadFix, Applicative, Alternative, MonadPlus, …
  • Monad STMDefined in ghc-internal-9.1003.0 · GHC.Internal.Conc.Sync
  • Functor STMDefined in ghc-internal-9.1003.0 · GHC.Internal.Conc.Sync
  • MonadFix STMDefined in stm-2.5.3.1 · Control.Monad.STM · orphan
  • Applicative STMDefined in ghc-internal-9.1003.0 · GHC.Internal.Conc.Sync
  • Alternative STMDefined in ghc-internal-9.1003.0 · GHC.Internal.Conc.Sync

    Takes the first non-retrying STM action.

  • MonadPlus STMDefined in ghc-internal-9.1003.0 · GHC.Internal.Conc.Sync

    Takes the first non-retrying STM action.

  • MonadCatch STMDefined in exceptions-0.10.9 · Control.Monad.Catch
  • MonadThrow STMDefined in exceptions-0.10.9 · Control.Monad.Catch
  • MonadBase STM STMDefined in transformers-base-0.4.6 · Control.Monad.Base
  • MonadBaseControl STM STMDefined in monad-control-1.0.3.1 · Control.Monad.Trans.Control
  • MArray TArray e STMDefined in stm-2.5.3.1 · Control.Concurrent.STM.TArray
  • Semigroup a => Semigroup (STM a)Defined in ghc-internal-9.1003.0 · GHC.Internal.Conc.Sync
  • Monoid a => Monoid (STM a)Defined in ghc-internal-9.1003.0 · GHC.Internal.Conc.Sync
  • type StM STM a = aDefined in monad-control-1.0.3.1 · Control.Monad.Trans.Control
valueretry :: STM a
#

Retry execution of the current memory transaction because it has seen values in TVars which mean that it should not continue (e.g. the TVars represent a shared buffer that is now empty). The implementation may block the thread until one of the TVars that it has read from has been updated. (GHC only)

valueorElse :: STM a -> STM a -> STM a
#

Compose two alternative STM actions (GHC only).

If the first action completes without retrying then it forms the result of the orElse. Otherwise, if the first action retries, then the second action is tried in its place. If both actions retry then the orElse as a whole retries.

valuecheck :: Bool -> STM ()
#

Check that the boolean condition is true and, if not, retry.

In other words, check b = unless b retry.

valuethrowSTM :: Exception e => e -> STM a
#

A variant of throw that can only be used within the STM monad.

Throwing an exception in STM aborts the transaction and propagates the exception. If the exception is caught via catchSTM, only the changes enclosed by the catch are rolled back; changes made outside of catchSTM persist.

If the exception is not caught inside of the STM, it is re-thrown by atomically, and the entire STM is rolled back.

Although throwSTM has a type that is an instance of the type of throw, the two functions are subtly different:

throw e    `seq` x  ===> throw e
throwSTM e `seq` x  ===> x

The first example will cause the exception e to be raised, whereas the second one won't. In fact, throwSTM will only cause an exception to be raised when it is used within the STM monad. The throwSTM variant should be used in preference to throw to raise an exception within the STM monad because it guarantees ordering with respect to other STM operations, whereas throw does not.

valuecatchSTM :: Exception e => STM a -> (e -> STM a) -> STM a
#

Exception handling within STM actions.

catchSTM m f catches any exception thrown by m using throwSTM, using the function f to handle the exception. If an exception is thrown, any changes made by m are rolled back, but changes prior to m persist.

TVar

11 declarations
datadata TVar a
#

Shared memory locations that support atomic memory transactions.

Instances1Eq
  • Eq (TVar a)Defined in ghc-internal-9.1003.0 · GHC.Internal.Conc.Sync
valuemodifyTVar :: TVar a -> (a -> a) -> STM ()
#

Mutate the contents of a TVar. N.B., this version is non-strict.

TMVar

14 declarations
newtypenewtype TMVar a
#

A TMVar is a synchronising variable, used for communication between concurrent threads. It can be thought of as a box, which may be empty or full.

Instances1Eq
  • Eq (TMVar a)Defined in stm-2.5.3.1 · Control.Concurrent.STM.TMVar

TChan

14 declarations
datadata TChan a
#

TChan is an abstract type representing an unbounded FIFO channel.

Instances1Eq
  • Eq (TChan a)Defined in stm-2.5.3.1 · Control.Concurrent.STM.TChan
valuenewBroadcastTChan :: STM (TChan a)
#

Create a write-only TChan. More precisely, readTChan will retry even after items have been written to the channel. The only way to read a broadcast channel is to duplicate it with dupTChan.

Consider a server that broadcasts messages to clients:

serve :: TChan Message -> Client -> IO loop
serve broadcastChan client = do
    myChan <- dupTChan broadcastChan
    forever $ do
        message <- readTChan myChan
        send client message

The problem with using newTChan to create the broadcast channel is that if it is only written to and never read, items will pile up in memory. By using newBroadcastTChan to create the broadcast channel, items can be garbage collected after clients have seen them.

valuedupTChan :: TChan a -> STM (TChan a)
#

Duplicate a TChan: the duplicate channel begins empty, but data written to either channel from then on will be available from both. Hence this creates a kind of broadcast channel, where data written by anyone is seen by everyone else.

valuecloneTChan :: TChan a -> STM (TChan a)
#

Clone a TChan: similar to dupTChan, but the cloned channel starts with the same content available as the original channel.

valuepeekTChan :: TChan a -> STM a
#

Get the next value from the TChan without removing it, retrying if the channel is empty.

valueunGetTChan :: TChan a -> a -> STM ()
#

Put a data item back onto a channel, where it will be the next item read.

TQueue

11 declarations
datadata TQueue a
#

TQueue is an abstract type representing an unbounded FIFO channel.

Instances1Eq
  • Eq (TQueue a)Defined in stm-2.5.3.1 · Control.Concurrent.STM.TQueue
valuepeekTQueue :: TQueue a -> STM a
#

Get the next value from the TQueue without removing it, retrying if the channel is empty.

valueflushTQueue :: TQueue a -> STM [a]
#

Efficiently read the entire contents of a TQueue into a list. This function never retries.

valueunGetTQueue :: TQueue a -> a -> STM ()
#

Put a data item back onto a channel, where it will be the next item read.

TBQueue

13 declarations
datadata TBQueue a
#

TBQueue is an abstract type representing a bounded FIFO channel.

Instances1Eq
  • Eq (TBQueue a)Defined in stm-2.5.3.1 · Control.Concurrent.STM.TBQueue
valuepeekTBQueue :: TBQueue a -> STM a
#

Get the next value from the TBQueue without removing it, retrying if the channel is empty.

valueunGetTBQueue :: TBQueue a -> a -> STM ()
#

Put a data item back onto a channel, where it will be the next item read. Blocks if the queue is full.