concurrent-effectful-0.1: Thread effects
Safe HaskellNone
LanguageGHC2021

Effectful.Concurrent.Static

Description

Synopsis

Effect

data Concurrent (a :: Type -> Type) b Source #

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:

>>> import Effectful.Reader.Static qualified as R
>>> printAsk msg = liftIO . putStrLn . (msg ++) . (": " ++) =<< R.ask
>>> :{
  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): LOCAL
parent (inside): LOCAL
parent (outside): GLOBAL
child (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:

>>> import Effectful.State.Static.Local qualified as SL
>>> :{
  runEff . SL.execState "Hi" . runConcurrent $ do
    replicateConcurrently_ 3 $ SL.modify (++ "!")
:}
"Hi"
>>> import Effectful.State.Static.Shared qualified 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.

Instances

Instances details
type DispatchOf Concurrent 
Instance details

Defined in Effectful.Concurrent.Effect

data StaticRep Concurrent 
Instance details

Defined in Effectful.Concurrent.Effect

labelThread :: forall (es :: [Effect]). (Concurrent :> es, HasCallStack) => ThreadId -> String -> Eff es () Source #

Lifted labelThread.

Since: 0.1

threadLabel :: forall (es :: [Effect]). (Concurrent :> es, HasCallStack) => ThreadId -> Eff es (Maybe String) Source #

Lifted threadLabel.

Since: 0.1

Functions

microsleep :: forall (es :: [Effect]). (Concurrent :> es, HasCallStack) => Natural -> Eff es () Source #

threadDelay in terms of unbounded Natural rather than Int i.e. runs sleep in the current thread for the specified number of microseconds.

Since: 0.1

sleep :: forall (es :: [Effect]). (Concurrent :> es, HasCallStack) => Natural -> Eff es () Source #

Runs sleep in the current thread for the specified number of seconds.

Since: 0.1

Re-exports

data Natural #

Natural number

Invariant: numbers <= 0xffffffffffffffff use the NS constructor

Instances

Instances details
PrintfArg Natural

Since: base-4.8.0.0

Instance details

Defined in Text.Printf

Enum Natural

@since base-4.8.0.0

Instance details

Defined in GHC.Internal.Enum

Num Natural

Note that Natural's Num instance isn't a ring: no element but 0 has an additive inverse. It is a semiring though.

@since base-4.8.0.0

Instance details

Defined in GHC.Internal.Num

Integral Natural

@since base-4.8.0.0

Instance details

Defined in GHC.Internal.Real

Real Natural

@since base-4.8.0.0

Instance details

Defined in GHC.Internal.Real

Eq Natural 
Instance details

Defined in GHC.Num.Natural

Methods

(==) :: Natural -> Natural -> Bool #

(/=) :: Natural -> Natural -> Bool #

Ord Natural 
Instance details

Defined in GHC.Num.Natural

KnownNat n => HasResolution (n :: Nat)

For example, Fixed 1000 will give you a Fixed with a resolution of 1000.

Instance details

Defined in Data.Fixed

Methods

resolution :: p n -> Integer #