HORIZON HASKELLDocslts/ghc-9.10.x248f8f02026-10-05Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05

  • Packagerio-0.1.22.0
  • Exports434
  • LanguageHaskell2010
  • LicenceMIT
  • SourceRIO.hs

Custom Prelude

0 declarations

One of the core features of rio is that it can be used as a Prelude replacement. Therefore it is best to disable the default Prelude with: NoImplicitPrelude pragma:

{-# LANGUAGE NoImplicitPrelude #-}
import RIO

Some functions not exported here can be found in RIO.Partial: fromJust, read, toEnum, pred, succ.

The RIO Monad

3 declarations
newtypenewtype RIO env a
#

The Reader+IO monad. This is different from a ReaderT because:

  • It's not a transformer, it hardcodes IO for simpler usage and error messages.

  • Instances of typeclasses like MonadLogger are implemented using classes defined on the environment, instead of using an underlying monad.

Constructors

Instances13MonadReader, MonadState, MonadWriter, Monad, Functor, Applicative, …
valuerunRIO :: MonadIO m => env -> RIO env a -> m a
#

Using the environment run in IO the action that requires that environment.

SimpleApp

If all you need is just some default environment that does basic logging and allows spawning processes, then you can use SimpleApp:

{-# LANGUAGE OverloadedStrings #-}
module Main where

main :: IO ()
main =
  runSimpleApp $ do
    logInfo "Hello World!"

Note the OverloadedStrings extension, which is enabled to simplify logging.

MonadIO and MonadUnliftIO

9 declarations
newtypenewtype UnliftIO (m :: Type -> Type)
#

The ability to run any monadic action m a as IO a.

This is more precisely a natural transformation. We need to new datatype (instead of simply using a forall) due to lack of support in GHC for impredicative types.

Constructors

classclass Monad m => MonadIO (m :: Type -> Type) where
#

Monads in which IO computations may be embedded. Any monad built by applying a sequence of monad transformers to the IO monad will be an instance of this class.

Instances should satisfy the following laws, which state that liftIO is a transformer of monads:

Methods

  • liftIO :: IO a -> m a

    Lift a computation from the IO monad. This allows us to run IO computations in any monadic stack, so long as it supports these kinds of operations (i.e. IO is the base monad for the stack).

    Example
    import Control.Monad.Trans.State -- from the "transformers" library
    
    printState :: Show s => StateT s IO ()
    printState = do
      state <- get
      liftIO $ print state

    Had we omitted liftIO, we would have ended up with this error:

    • Couldn't match type ‘IO’ with ‘StateT s IO’
     Expected type: StateT s IO ()
       Actual type: IO ()

    The important part here is the mismatch between StateT s IO () and IO ().

    Luckily, we know of a function that takes an IO a and returns an (m a): liftIO, enabling us to run the program and see the expected results:

    > evalStateT printState "hello"
    "hello"
    
    > evalStateT printState 3
    3
    
Instances19MonadIO, …
valueaskRunInIO :: MonadUnliftIO m => m (m a -> IO a)
#

Same as askUnliftIO, but returns a monomorphic function instead of a polymorphic newtype wrapper. If you only need to apply the transformation on one concrete type, this function can be more convenient.

valueliftIOOp :: MonadUnliftIO m => (IO a -> IO b) -> m a -> m b
#

A helper function for lifting IO a -> IO b functions into any MonadUnliftIO.

Example
liftedTry :: (Exception e, MonadUnliftIO m) => m a -> m (Either e a)
liftedTry m = liftIOOp Control.Exception.try m
valuewrappedWithRunInIO
  1. :: MonadUnliftIO n
  2. => (n b -> m b)

    The wrapper, for instance IdentityT.

  3. -> (forall a. m a -> n a)

    The inverse, for instance runIdentityT.

  4. -> ((forall a. m a -> IO a) -> IO b)

    The actual function to invoke withRunInIO with.

  5. -> m b
#

A helper function for implementing MonadUnliftIO instances. Useful for the common case where you want to simply delegate to the underlying transformer.

Note: You can derive MonadUnliftIO for newtypes without this helper function in unliftio-core 0.2.0.0 and later.

Example
newtype AppT m a = AppT { unAppT :: ReaderT Int (ResourceT m) a }
  deriving (Functor, Applicative, Monad, MonadIO)

-- Same as `deriving newtype (MonadUnliftIO)`
instance MonadUnliftIO m => MonadUnliftIO (AppT m) where
  withRunInIO = wrappedWithRunInIO AppT unAppT
classclass MonadIO m => MonadUnliftIO (m :: Type -> Type) where
#

Monads which allow their actions to be run in IO.

While MonadIO allows an IO action to be lifted into another monad, this class captures the opposite concept: allowing you to capture the monadic context. Note that, in order to meet the laws given below, the intuition is that a monad must have no monadic state, but may have monadic context. This essentially limits MonadUnliftIO to ReaderT and IdentityT transformers on top of IO.

Laws. For any function run provided by withRunInIO, it must meet the monad transformer laws as reformulated for MonadUnliftIO:

  • run . return = return
  • run (m >>= f) = run m >>= run . f

Instances of MonadUnliftIO must also satisfy the following laws:

Identity law

withRunInIO (\run -> run m) = m

Inverse law

withRunInIO (\_ -> m) = liftIO m

As an example of an invalid instance, a naive implementation of MonadUnliftIO (StateT s m) might be

withRunInIO inner =
  StateT $ \s ->
    withRunInIO $ \run ->
      inner (run . flip evalStateT s)

This breaks the identity law because the inner run m would throw away any state changes in m.

Methods

  • withRunInIO :: ((forall a. m a -> IO a) -> IO b) -> m b

    Convenience function for capturing the monadic context and running an IO action with a runner function. The runner function is used to run a monadic action m in IO.

Instances4MonadUnliftIO

Logger

52 declarations

The logging system in RIO is built upon "log functions", which are accessed in RIO's environment via a class like "has log function". There are two provided:

  • In the common case: for logging plain text (via Utf8Builder) efficiently, there is LogFunc, which can be created via withLogFunc, and is accessed via HasLogFunc. This provides all the classical logging facilities: timestamped text output with log levels and colors (if terminal-supported) to the terminal. We log output via logInfo, logDebug, etc.

  • In the advanced case: where logging takes on a more semantic meaning and the logs need to be digested, acted upon, translated or serialized upstream (to e.g. a JSON logging server), we have GLogFunc (as in "generic log function"), and is accessed via HasGLogFunc. In this case, we log output via glog. See the Type-generic logger section for more information.

valuewithLogFunc :: MonadUnliftIO m => LogOptions -> (LogFunc -> m a) -> m a
#

Given a LogOptions value, run the given function with the specified LogFunc. A common way to use this function is:

let isVerbose = False -- get from the command line instead
logOptions' <- logOptionsHandle stderr isVerbose
let logOptions = setLogUseTime True logOptions'
withLogFunc logOptions $ \lf -> do
  let app = App -- application specific environment
        { appLogFunc = lf
        , appOtherStuff = ...
        }
  runRIO app $ do
    logInfo "Starting app"
    myApp
datadata LogFunc
#

A logging function, wrapped in a newtype for better error messages.

An implementation may choose any behavior of this value it wishes, including printing to standard output or no action at all.

Instances3Semigroup, Monoid, HasLogFunc
valuelogOptionsHandle
  1. :: MonadIO m
  2. => Handle
  3. -> Bool

    Verbose Flag

  4. -> m LogOptions
#

Create a LogOptions value from the given Handle and whether to perform verbose logging or not. Individiual settings can be overridden using appropriate set functions. Logging output is guaranteed to be non-interleaved only for a UTF-8 Handle in a multi-thread environment.

When Verbose Flag is True, the following happens:

  • setLogVerboseFormat is called with True

  • setLogUseColor is called with True (except on Windows)

  • setLogUseLoc is called with True

  • setLogUseTime is called with True

  • setLogMinLevel is called with Debug log level

valuelogSticky
  1. :: (MonadIO m, HasCallStack, MonadReader env m, HasLogFunc env)
  2. => Utf8Builder
  3. -> m ()
#

Write a "sticky" line to the terminal. Any subsequent lines will overwrite this one, and that same line will be repeated below again. In other words, the line sticks at the bottom of the output forever. Running this function again will replace the sticky line with a new sticky line. When you want to get rid of the sticky line, run logStickyDone.

Note that not all LogFunc implementations will support sticky messages as described. However, the withLogFunc implementation provided by this module does.

Create a LogOptions value which will store its data in memory. This is primarily intended for testing purposes. This will return both a LogOptions value and an IORef containing the resulting Builder value.

This will default to non-verbose settings and assume there is a terminal attached. These assumptions can be overridden using the appropriate set functions.

typetype LogSource = Text
#

Where in the application a log message came from. Used for display purposes only.

datadata CallStack
#

CallStacks are a lightweight method of obtaining a partial call-stack at any point in the program.

A function can request its call-site with the HasCallStack constraint. For example, we can define

putStrLnWithCallStack :: HasCallStack => String -> IO ()

as a variant of putStrLn that will get its call-site and print it, along with the string given as argument. We can access the call-stack inside putStrLnWithCallStack with callStack.

Example1 expression
:{putStrLnWithCallStack :: HasCallStack => String -> IO ()putStrLnWithCallStack msg = do  putStrLn msg  putStrLn (prettyCallStack callStack):}

Thus, if we call putStrLnWithCallStack we will get a formatted call-stack alongside our string.

Example1 expression
putStrLnWithCallStack "hello"helloCallStack (from HasCallStack):  putStrLnWithCallStack, called at <interactive>:... in interactive:Ghci...

GHC solves HasCallStack constraints in three steps:

  1. If there is a CallStack in scope -- i.e. the enclosing function has a HasCallStack constraint -- GHC will append the new call-site to the existing CallStack.

  2. If there is no CallStack in scope -- e.g. in the GHCi session above -- and the enclosing definition does not have an explicit type signature, GHC will infer a HasCallStack constraint for the enclosing definition (subject to the monomorphism restriction).

  3. If there is no CallStack in scope and the enclosing definition has an explicit type signature, GHC will solve the HasCallStack constraint for the singleton CallStack containing just the current call-site.

CallStacks do not interact with the RTS and do not require compilation with -prof. On the other hand, as they are built up explicitly via the HasCallStack constraints, they will generally not contain as much information as the simulated call-stacks maintained by the RTS.

A CallStack is a [(String, SrcLoc)]. The String is the name of function that was called, the SrcLoc is the call-site. The list is ordered with the most recently called function at the head.

NOTE: The intrepid user may notice that HasCallStack is just an alias for an implicit parameter ?callStack :: CallStack. This is an implementation detail and should not be considered part of the CallStack API, we may decide to change the implementation in the future.

Instances4IsList, Show, NFData, Item
valuenoLogging :: (HasLogFunc env, MonadReader env m) => m a -> m a
#

Disable logging capabilities in a given sub-routine

Intended to skip logging in general purpose implementations, where secrets might be logged accidently.

newtypenewtype GLogFunc msg
#

A generic logger of some type msg.

Your GLocFunc can re-use the existing classical logging framework of RIO, and/or implement additional transforms, filters. Alternatively, you may log to a JSON source in a database, or anywhere else as needed. You can decide how to log levels or severities based on the constructors in your type. You will normally determine this in your main app entry point.

Instances5Contravariant, Semigroup, Monoid, HasGLogFunc, GMsg
  • Contravariant GLogFuncDefined in rio-0.1.22.0 · RIO.Prelude.Logger

    Use this instance to wrap sub-loggers via mapRIO.

    The Contravariant class is available in base 4.12.0.

  • Semigroup (GLogFunc msg)Defined in rio-0.1.22.0 · RIO.Prelude.Logger

    Perform both sets of actions per log entry.

  • Monoid (GLogFunc msg)Defined in rio-0.1.22.0 · RIO.Prelude.Logger

    mempty peforms no logging.

  • HasGLogFunc (GLogFunc msg)Defined in rio-0.1.22.0 · RIO.Prelude.Logger

    Quick way to run a RIO that only has a logger in its environment.

  • type GMsg (GLogFunc msg) = msgDefined in rio-0.1.22.0 · RIO.Prelude.Logger
valuemkGLogFunc :: (CallStack -> msg -> IO ()) -> GLogFunc msg
#

Make a custom generic logger. With this you could, for example, write to a database or a log digestion service. For example:

mkGLogFunc (\stack msg -> send (Data.Aeson.encode (JsonLog stack msg)))
classclass HasGLogFunc env where
#

An app is capable of generic logging if it implements this.

Associated types

  • type family GMsg env

Methods

Instances1HasGLogFunc
  • HasGLogFunc (GLogFunc msg)Defined in rio-0.1.22.0 · RIO.Prelude.Logger

    Quick way to run a RIO that only has a logger in its environment.

classclass HasLogLevel msg where
#

Level, if any, of your logs. If unknown, use LogOther. Use for your generic log data types that want to sit inside the classic log framework.

Methods

classclass HasLogSource msg where
#

Source of a log. This can be whatever you want. Use for your generic log data types that want to sit inside the classic log framework.

Methods

familytype family GMsg env
#
Instances1GMsg
  • type GMsg (GLogFunc msg) = msgDefined in rio-0.1.22.0 · RIO.Prelude.Logger

Display

7 declarations
classclass Display a where
#

A typeclass for values which can be converted to a Utf8Builder. The intention of this typeclass is to provide a human-friendly display of the data.

Methods

Instances20Display, …

Optics

18 declarations

microlens-based Lenses, Traversals, etc.

typetype Lens s t a b = forall (f :: Type -> Type). Functor f => (a -> f b) -> s -> f t
#

Lens s t a b is the lowest common denominator of a setter and a getter, something that has the power of both; it has a Functor constraint, and since both Const and Identity are functors, it can be used whenever a getter or a setter is needed.

  • a is the type of the value inside of structure

  • b is the type of the replaced value

  • s is the type of the whole structure

  • t is the type of the structure after replacing a in it with b

valuelens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
#

lens creates a Lens from a getter and a setter. The resulting lens isn't the most effective one (because of having to traverse the structure twice when modifying), but it shouldn't matter much.

A (partial) lens for list indexing:

ix :: Int -> Lens' [a] a
ix i = lens (!! i)                                   -- getter
            (\s b -> take i s ++ b : drop (i+1) s)   -- setter

Usage:

>>> [1..9] ^. ix 3
4

>>> [1..9] & ix 3 %~ negate
[1,2,3,-4,5,6,7,8,9]

When getting, the setter is completely unused; when setting, the getter is unused. Both are used only when the value is being modified. For instance, here we define a lens for the 1st element of a list, but instead of a legitimate getter we use undefined. Then we use the resulting lens for setting and it works, which proves that the getter wasn't used:

Example1 expression
[1,2,3] & lens undefined (\s b -> b : tail s) .~ 10[10,2,3]
valueview :: MonadReader s m => Getting a s a -> m a
#

view is a synonym for (^.), generalised for MonadReader (we are able to use it instead of (^.) since functions are instances of the MonadReader class):

Example1 expression
view _1 (1, 2)1

When you're using Reader for config and your config type has lenses generated for it, most of the time you'll be using view instead of asks:

doSomething :: (MonadReader Config m) => m Int
doSomething = do
  thingy        <- view setting1  -- same as “asks (^. setting1)”
  anotherThingy <- view setting2
  ...
typetype ASetter s t a b = (a -> Identity b) -> s -> Identity t
#

ASetter s t a b is something that turns a function modifying a value into a function modifying a structure. If you ignore Identity (as Identity a is the same thing as a), the type is:

type ASetter s t a b = (a -> b) -> s -> t

The reason Identity is used here is for ASetter to be composable with other types, such as Lens.

Technically, if you're writing a library, you shouldn't use this type for setters you are exporting from your library; the right type to use is Setter, but it is not provided by this package (because then it'd have to depend on distributive). It's completely alright, however, to export functions which take an ASetter as an argument.

typetype ASetter' s a = ASetter s s a a
#

This is a type alias for monomorphic setters which don't change the type of the container (or of the value inside). It's useful more often than the same type in lens, because we can't provide real setters and so it does the job of both ASetter' and Setter'.

typetype Getting r s a = (a -> Const r a) -> s -> Const r s
#

Functions that operate on getters and folds – such as (^.), (^..), (^?) – use Getter r s a (with different values of r) to describe what kind of result they need. For instance, (^.) needs the getter to be able to return a single value, and so it accepts a getter of type Getting a s a. (^..) wants the getter to gather values together, so it uses Getting (Endo [a]) s a (it could've used Getting [a] s a instead, but it's faster with Endo). The choice of r depends on what you want to do with elements you're extracting from s.

typetype Lens' s a = Lens s s a a
#

This is a type alias for monomorphic lenses which don't change the type of the container (or of the value inside).

typetype SimpleGetter s a = forall r. Getting r s a
#

A SimpleGetter s a extracts a from s; so, it's the same thing as (s -> a), but you can use it in lens chains because its type looks like this:

type SimpleGetter s a =
  forall r. (a -> Const r a) -> s -> Const r s

Since Const r is a functor, SimpleGetter has the same shape as other lens types and can be composed with them. To get (s -> a) out of a SimpleGetter, choose r ~ a and feed Const :: a -> Const a a to the getter:

-- the actual signature is more permissive:
-- view :: Getting a s a -> s -> a
view :: SimpleGetter s a -> s -> a
view getter = getConst . getter Const

The actual Getter from lens is more general:

type Getter s a =
  forall f. (Contravariant f, Functor f) => (a -> f a) -> s -> f s

I'm not currently aware of any functions that take lens's Getter but won't accept SimpleGetter, but you should try to avoid exporting SimpleGetters anyway to minimise confusion. Alternatively, look at microlens-contra, which provides a fully lens-compatible Getter.

Lens users: you can convert a SimpleGetter to Getter by applying to . view to it.

valueover :: ASetter s t a b -> (a -> b) -> s -> t
#

over is a synonym for (%~).

Getting fmap in a roundabout way:

over mapped :: Functor f => (a -> b) -> f a -> f b
over mapped = fmap

Applying a function to both components of a pair:

over both :: (a -> b) -> (a, a) -> (b, b)
over both = \f t -> (f (fst t), f (snd t))

Using over _2 as a replacement for second:

Example1 expression
over _2 show (10,20)(10,"20")
valueset :: ASetter s t a b -> b -> s -> t
#

set is a synonym for (.~).

Setting the 1st component of a pair:

set _1 :: x -> (a, b) -> (x, b)
set _1 = \x t -> (x, snd t)

Using it to rewrite (Data.Functor.<$):

set mapped :: Functor f => a -> f b -> f a
set mapped = (Data.Functor.<$)
valuesets :: ((a -> b) -> s -> t) -> ASetter s t a b
#

sets creates an ASetter from an ordinary function. (The only thing it does is wrapping and unwrapping Identity.)

valueto :: (s -> a) -> SimpleGetter s a
#

to creates a getter from any function:

a ^. to f = f a

It's most useful in chains, because it lets you mix lenses and ordinary functions. Suppose you have a record which comes from some third-party library and doesn't have any lens accessors. You want to do something like this:

value ^. _1 . field . at 2

However, field isn't a getter, and you have to do this instead:

field (value ^. _1) ^. at 2

but now value is in the middle and it's hard to read the resulting code. A variant with to is prettier and more readable:

value ^. _1 . to field . at 2
value(^.) :: s -> Getting a s a -> a
#

(^.) applies a getter to a value; in other words, it gets a value out of a structure using a getter (which can be a lens, traversal, fold, etc.).

Getting 1st field of a tuple:

(^. _1) :: (a, b) -> a
(^. _1) = fst

When (^.) is used with a traversal, it combines all results using the Monoid instance for the resulting type. For instance, for lists it would be simple concatenation:

Example1 expression
("str","ing") ^. each"string"

The reason for this is that traversals use Applicative, and the Applicative instance for Const uses monoid concatenation to combine “effects” of Const.

A non-operator version of (^.) is called view, and it's a bit more general than (^.) (it works in MonadReader). If you need the general version, you can get it from microlens-mtl; otherwise there's view available in Lens.Micro.Extras.

value(^?) :: s -> Getting (First a) s a -> Maybe a
#

s ^? t returns the 1st element t returns, or Nothing if t doesn't return anything. It's trivially implemented by passing the First monoid to the getter.

Safe head:

Example1 expression
[] ^? eachNothing
Example1 expression
[1..3] ^? eachJust 1

Converting Either to Maybe:

Example1 expression
Left 1 ^? _RightNothing
Example1 expression
Right 1 ^? _RightJust 1

A non-operator version of (^?) is called preview, and – like view – it's a bit more general than (^?) (it works in MonadReader). If you need the general version, you can get it from microlens-mtl; otherwise there's preview available in Lens.Micro.Extras.

value(^..) :: s -> Getting (Endo [a]) s a -> [a]
#

s ^.. t returns the list of all values that t gets from s.

A Maybe contains either 0 or 1 values:

Example1 expression
Just 3 ^.. _Just[3]

Gathering all values in a list of tuples:

Example1 expression
[(1,2),(3,4)] ^.. each.each[1,2,3,4]
value(%~) :: ASetter s t a b -> (a -> b) -> s -> t
#

(%~) applies a function to the target; an alternative explanation is that it is an inverse of sets, which turns a setter into an ordinary function. mapped %~ reverse is the same thing as fmap reverse.

See over if you want a non-operator synonym.

Negating the 1st element of a pair:

Example1 expression
(1,2) & _1 %~ negate(-1,2)

Turning all Lefts in a list to upper case:

Example1 expression
(mapped._Left.mapped %~ toUpper) [Left "foo", Right "bar"][Left "FOO",Right "bar"]
value(.~) :: ASetter s t a b -> b -> s -> t
#

(.~) assigns a value to the target. It's the same thing as using (%~) with const:

l .~ x = l %~ const x

See set if you want a non-operator synonym.

Here it is used to change 2 fields of a 3-tuple:

Example1 expression
(0,0,0) & _1 .~ 1 & _3 .~ 3(1,0,3)

Concurrency

7 declarations
datadata ThreadId
#

A ThreadId is an abstract type representing a handle to a thread. ThreadId is an instance of Eq, Ord and Show, where the Ord instance implements an arbitrary total ordering over ThreadIds. The Show instance lets you convert an arbitrary-valued ThreadId to string form; showing a ThreadId value is occasionally useful when debugging or diagnosing the behaviour of a concurrent program.

Note: in GHC, if you have a ThreadId, you essentially have a pointer to the thread itself. This means the thread itself can't be garbage collected until you drop the ThreadId. This misfeature would be difficult to correct while continuing to support threadStatus.

Instances5Eq, Ord, Show, NFData, Hashable
  • Eq ThreadIdDefined in ghc-internal-9.1003.0 · GHC.Internal.Conc.Sync
  • Ord ThreadIdDefined in ghc-internal-9.1003.0 · GHC.Internal.Conc.Sync
  • Show ThreadIdDefined in ghc-internal-9.1003.0 · GHC.Internal.Conc.Sync
  • NFData ThreadIdDefined in deepseq-1.5.0.0 · Control.DeepSeq
  • Hashable ThreadIdDefined in hashable-1.4.7.0 · Data.Hashable.Class

Async

datadata Async a
#

An asynchronous action spawned by async or withAsync. Asynchronous actions are executed in a separate thread, and operations are provided for waiting for asynchronous actions to complete and obtaining their results (see e.g. wait).

Instances4Functor, Eq, Ord, Hashable
  • Functor AsyncDefined in async-2.2.5 · Control.Concurrent.Async.Internal
  • Eq (Async a)Defined in async-2.2.5 · Control.Concurrent.Async.Internal
  • Ord (Async a)Defined in async-2.2.5 · Control.Concurrent.Async.Internal
  • Hashable (Async a)Defined in async-2.2.5 · Control.Concurrent.Async.Internal
datadata Conc (m :: Type -> Type) a where
#

A more efficient alternative to Concurrently, which reduces the number of threads that need to be forked. For more information, see this blog post. This is provided as a separate type to Concurrently as it has a slightly different API.

Use the conc function to construct values of type Conc, and runConc to execute the composed actions. You can use the Applicative instance to run different actions and wait for all of them to complete, or the Alternative instance to wait for the first thread to complete.

In the event of a runtime exception thrown by any of the children threads, or an asynchronous exception received in the parent thread, all threads will be killed with an AsyncCancelled exception and the original exception rethrown. If multiple exceptions are generated by different threads, there are no guarantees on which exception will end up getting rethrown.

For many common use cases, you may prefer using helper functions in this module like mapConcurrently.

There are some intentional differences in behavior to Concurrently:

  • Children threads are always launched in an unmasked state, not the inherited state of the parent thread.

Note that it is a programmer error to use the Alternative instance in such a way that there are no alternatives to an empty, e.g. runConc (empty | empty). In such a case, a ConcException will be thrown. If there was an Alternative in the standard libraries without empty, this library would use it instead.

Instances5Functor, Applicative, Alternative, Semigroup, Monoid
datadata ConcException
#

Things that can go wrong in the structure of a Conc. These are programmer errors.

Instances6Eq, Ord, Show, Generic, Exception, Rep
newtypenewtype Concurrently (m :: Type -> Type) a
#

Unlifted Concurrently.

Constructors

Instances5Functor, Applicative, Alternative, Semigroup, Monoid
valuepooledMapConcurrentlyN
  1. :: (MonadUnliftIO m, Traversable t)
  2. => Int

    Max. number of threads. Should not be less than 1.

  3. -> (a -> m b)
  4. -> t a
  5. -> m (t b)
#

Like mapConcurrently from async, but instead of one thread per element, it does pooling from a set of threads. This is useful in scenarios where resource consumption is bounded and for use cases where too many concurrent tasks aren't allowed.

Example usage
import Say

action :: Int -> IO Int
action n = do
  tid <- myThreadId
  sayString $ show tid
  threadDelay (2 * 10^6) -- 2 seconds
  return n

main :: IO ()
main = do
  yx <- pooledMapConcurrentlyN 5 (\x -> action x) [1..5]
  print yx

On executing you can see that five threads have been spawned:

$ ./pool
ThreadId 36
ThreadId 38
ThreadId 40
ThreadId 42
ThreadId 44
[1,2,3,4,5]

Let's modify the above program such that there are less threads than the number of items in the list:

import Say

action :: Int -> IO Int
action n = do
  tid <- myThreadId
  sayString $ show tid
  threadDelay (2 * 10^6) -- 2 seconds
  return n

main :: IO ()
main = do
  yx <- pooledMapConcurrentlyN 3 (\x -> action x) [1..5]
  print yx

On executing you can see that only three threads are active totally:

$ ./pool
ThreadId 35
ThreadId 37
ThreadId 39
ThreadId 35
ThreadId 39
[1,2,3,4,5]

STM

newtypenewtype STM a
#

A monad supporting atomic memory transactions.

Instances11Monad, 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
  • 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
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.

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.

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.

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.

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.

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.

valuewriteTMVar :: TMVar a -> a -> STM ()
#

Non-blocking write of a new value to a TMVar Puts if empty. Replaces if populated.

valuepeekTQueue :: TQueue a -> STM a
#

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

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

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

valuemodifyTVar :: TVar a -> (a -> a) -> STM ()
#

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

valuestateTVar :: TVar s -> (s -> (a, s)) -> STM a
#

Like modifyTVar' but the function is a simple state transition that can return a side value which is passed on as the result of the STM.

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
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
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
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
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

Chan

datadata Chan a
#

Chan is an abstract type representing an unbounded FIFO channel.

Instances1Eq
  • Eq (Chan a)Defined in base-4.20.2.0 · Control.Concurrent.Chan

Timeout

Exceptions

65 declarations
classclass (Typeable e, Show e) => Exception e where
#

Any type that you wish to throw or catch as an exception must be an instance of the Exception class. The simplest case is a new exception type directly below the root:

data MyException = ThisException | ThatException
    deriving Show

instance Exception MyException

The default method definitions in the Exception class do what we need in this case. You can now throw and catch ThisException and ThatException as exceptions:

*Main> throw ThisException `catch` \e -> putStrLn ("Caught " ++ show (e :: MyException))
Caught ThisException

In more complicated examples, you may wish to define a whole hierarchy of exceptions:

---------------------------------------------------------------------
-- Make the root exception type for all the exceptions in a compiler

data SomeCompilerException = forall e . Exception e => SomeCompilerException e

instance Show SomeCompilerException where
    show (SomeCompilerException e) = show e

instance Exception SomeCompilerException

compilerExceptionToException :: Exception e => e -> SomeException
compilerExceptionToException = toException . SomeCompilerException

compilerExceptionFromException :: Exception e => SomeException -> Maybe e
compilerExceptionFromException x = do
    SomeCompilerException a <- fromException x
    cast a

---------------------------------------------------------------------
-- Make a subhierarchy for exceptions in the frontend of the compiler

data SomeFrontendException = forall e . Exception e => SomeFrontendException e

instance Show SomeFrontendException where
    show (SomeFrontendException e) = show e

instance Exception SomeFrontendException where
    toException = compilerExceptionToException
    fromException = compilerExceptionFromException

frontendExceptionToException :: Exception e => e -> SomeException
frontendExceptionToException = toException . SomeFrontendException

frontendExceptionFromException :: Exception e => SomeException -> Maybe e
frontendExceptionFromException x = do
    SomeFrontendException a <- fromException x
    cast a

---------------------------------------------------------------------
-- Make an exception type for a particular frontend compiler exception

data MismatchedParentheses = MismatchedParentheses
    deriving Show

instance Exception MismatchedParentheses where
    toException   = frontendExceptionToException
    fromException = frontendExceptionFromException

We can now catch a MismatchedParentheses exception as MismatchedParentheses, SomeFrontendException or SomeCompilerException, but not other types, e.g. IOException:

*Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: MismatchedParentheses))
Caught MismatchedParentheses
*Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: SomeFrontendException))
Caught MismatchedParentheses
*Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: SomeCompilerException))
Caught MismatchedParentheses
*Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: IOException))
*** Exception: MismatchedParentheses

Methods

Instances44Exception, …
valueassert :: Bool -> a -> a
#

If the first argument evaluates to True, then the result is the second argument. Otherwise an AssertionFailed exception is raised, containing a String with the source file and line number of the call to assert.

Assertions can normally be turned on or off with a compiler flag (for GHC, assertions are normally on unless optimisation is turned on with -O or the -fignore-asserts option is given). When assertions are turned off, the first argument to assert is ignored, and the second argument is returned as the result.

classclass Typeable (a :: k) where
#

The class Typeable allows a concrete representation of a type to be calculated.

datadata SomeException
#

The SomeException type is the root of the exception type hierarchy. When an exception of type e is thrown, behind the scenes it is encapsulated in a SomeException.

Constructors

Instances3Show, Exception, Display
datadata IOException
#

Exceptions that occur in the IO monad. An IOException records a more specific error type, a descriptive string and maybe the handle that was used when the error was flagged.

Instances5Eq, Show, Exception, Display, MonadError
datadata StringException
#

Exception type thrown by throwString.

Note that the second field of the data constructor depends on GHC/base version. For base 4.9 and GHC 8.0 and later, the second field is a call stack. Previous versions of GHC and base do not support call stacks, and the field is simply unit (provided to make pattern matching across GHC versions easier).

Instances3Eq, Show, Exception
valuebracket :: MonadUnliftIO m => m a -> (a -> m b) -> (a -> m c) -> m c
#

Allocate and clean up a resource safely.

For more information on motivation and usage of this function, see base's bracket. This function has two differences from the one in base. The first, and more obvious, is that it works on any MonadUnliftIO instance, not just IO.

The more subtle difference is that this function will use uninterruptible masking for its cleanup handler. This is a subtle distinction, but at a high level, means that resource cleanup has more guarantees to complete. This comes at the cost that an incorrectly written cleanup function cannot be interrupted.

For more information, please see https://github.com/fpco/safe-exceptions/issues/3.

valuebracket_ :: MonadUnliftIO m => m a -> m b -> m c -> m c
#

Same as bracket, but does not pass the acquired resource to cleanup and use functions.

For more information, see base's bracket_.

valuecatch
  1. :: (MonadUnliftIO m, Exception e)
  2. => m a

    action

  3. -> (e -> m a)

    handler

  4. -> m a
#

Catch a synchronous (but not asynchronous) exception and recover from it.

This is parameterized on the exception type. To catch all synchronous exceptions, use catchAny.

valuecatchSyncOrAsync
  1. :: (MonadUnliftIO m, Exception e)
  2. => m a
  3. -> e -> m a
  4. -> m a
#

A variant of catch that catches both synchronous and asynchronous exceptions.

WARNING: This function (and other *SyncOrAsync functions) is for advanced users. Most of the time, you probably want to use the non-SyncOrAsync versions.

Before attempting to use this function, be familiar with the "Rules for async safe handling" section in this blog post.

valuecatches :: MonadUnliftIO m => m a -> [Handler m a] -> m a
#

Similar to catch, but provides multiple different handler functions.

For more information on motivation, see base's catches. Note that, unlike that function, this function will not catch asynchronous exceptions.

valuefinally
  1. :: MonadUnliftIO m
  2. => m a

    thing

  3. -> m b

    after

  4. -> m a
#

Perform thing, guaranteeing that after will run after, even if an exception occurs.

Same interruptible vs uninterrupible points apply as with bracket. See base's finally for more information.

valuepureTry :: a -> Either SomeException a
#

Evaluate the value to WHNF and catch any synchronous exceptions.

The expression may still have bottom values within it; you may instead want to use pureTryDeep.

valuethrowIO :: (MonadIO m, Exception e) => e -> m a
#

Synchronously throw the given exception.

Note that, if you provide an exception value which is of an asynchronous type, it will be wrapped up in SyncExceptionWrapper. See toSyncException.

valuethrowString :: (MonadIO m, HasCallStack) => String -> m a
#

A convenience function for throwing a user error. This is useful for cases where it would be too high a burden to define your own exception type.

This throws an exception of type StringException. When GHC supports it (base 4.9 and GHC 8.0 and onward), it includes a call stack.

Convert an exception into an asynchronous exception.

For asynchronous exceptions, this is the same as toException. For synchronous exceptions, this will wrap up the exception with AsyncExceptionWrapper.

Convert an exception into a synchronous exception.

For synchronous exceptions, this is the same as toException. For asynchronous exceptions, this will wrap up the exception with SyncExceptionWrapper.

valuetry :: (MonadUnliftIO m, Exception e) => m a -> m (Either e a)
#

Run the given action and catch any synchronous exceptions as a Left value.

This is parameterized on the exception type. To catch all synchronous exceptions, use tryAny.

Re-exported from Control.Monad.Catch:

methodthrowM :: (HasCallStack, Exception e) => e -> m a
#

Throw an exception. Note that this throws when this action is run in the monad m, not when it is applied. It is a generalization of Control.Exception's throwIO.

Should satisfy the law:

throwM e >> f = throwM e

Files and handles

41 declarations
datadata Handle
#

Haskell defines operations to read and write characters from and to files, represented by values of type Handle. Each value of this type is a handle: a record used by the Haskell run-time system to manage I/O with file system objects. A handle has at least the following properties:

  • whether it manages input or output or both;

  • whether it is open, closed or semi-closed;

  • whether the object is seekable;

  • whether buffering is disabled, or enabled on a line or block basis;

  • a buffer (whose length may be zero).

Most handles will also have a current I/O position indicating where the next input or output operation will occur. A handle is readable if it manages only input or both input and output; likewise, it is writable if it manages only output or both input and output. A handle is open when first allocated. Once it is closed it can no longer be used for either input or output, though an implementation cannot re-use its storage while references remain to it. Handles are in the Show and Eq classes. The string produced by showing a handle is system dependent; it should include enough information to identify the handle for debugging. A handle is equal according to == only to itself; no attempt is made to compare the internal state of different handles for equality.

Instances2Eq, Show
  • Eq HandleDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.Handle.Types
  • Show HandleDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.Handle.Types
datadata IOMode
#

See GHC.Internal.System.IO.openFile

Instances6Enum, Eq, Ord, Read, Show, Ix
  • Enum IOModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.IOMode
  • Eq IOModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.IOMode
  • Ord IOModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.IOMode
  • Read IOModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.IOMode
  • Show IOModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.IOMode
  • Ix IOModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.IOMode
valuegetMonotonicTime :: MonadIO m => m Double
#

Get the number of seconds which have passed since an arbitrary starting time, useful for calculating runtime in a program.

datadata SeekMode
#

A mode that determines the effect of GHC.Internal.System.IO.hSeek hdl mode i.

Constructors

  • AbsoluteSeek

    the position of hdl is set to i.

  • RelativeSeek

    the position of hdl is set to offset i from the current position.

  • SeekFromEnd

    the position of hdl is set to offset i from the end of the file.

Instances6Enum, Eq, Ord, Read, Show, Ix
  • Enum SeekModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.Device
  • Eq SeekModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.Device
  • Ord SeekModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.Device
  • Read SeekModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.Device
  • Show SeekModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.Device
  • Ix SeekModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.Device
datadata BufferMode
#

Three kinds of buffering are supported: line-buffering, block-buffering or no-buffering. These modes have the following effects. For output, items are written out, or flushed, from the internal buffer according to the buffer mode:

  • line-buffering: the entire output buffer is flushed whenever a newline is output, the buffer overflows, a GHC.Internal.System.IO.hFlush is issued, or the handle is closed.

  • block-buffering: the entire buffer is written out whenever it overflows, a GHC.Internal.System.IO.hFlush is issued, or the handle is closed.

  • no-buffering: output is written immediately, and never stored in the buffer.

An implementation is free to flush the buffer more frequently, but not less frequently, than specified above. The output buffer is emptied as soon as it has been written out.

Similarly, input occurs according to the buffer mode for the handle:

  • line-buffering: when the buffer for the handle is not empty, the next item is obtained from the buffer; otherwise, when the buffer is empty, characters up to and including the next newline character are read into the buffer. No characters are available until the newline character is available or the buffer is full.

  • block-buffering: when the buffer for the handle becomes empty, the next block of data is read into the buffer.

  • no-buffering: the next input item is read and returned. The GHC.Internal.System.IO.hLookAhead operation implies that even a no-buffered handle may require a one-character buffer.

The default buffering mode when a handle is opened is implementation-dependent and may depend on the file system object which is attached to that handle. For most implementations, physical files will normally be block-buffered and terminals will normally be line-buffered.

Constructors

  • NoBuffering

    buffering is disabled if possible.

  • LineBuffering

    line-buffering should be enabled if possible.

  • BlockBuffering (Maybe Int)

    block-buffering should be enabled if possible. The size of the buffer is n items if the argument is Just n and is otherwise implementation-dependent.

Instances4Eq, Ord, Read, Show
  • Eq BufferModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.Handle.Types
  • Ord BufferModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.Handle.Types
  • Read BufferModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.Handle.Types
  • Show BufferModeDefined in ghc-internal-9.1003.0 · GHC.Internal.IO.Handle.Types
valuewithTempDirectory
  1. :: MonadUnliftIO m
  2. => FilePath

    Temp directory to create the directory in.

  3. -> String

    Directory name template. See openTempFile.

  4. -> (FilePath -> m a)

    Callback that can use the directory.

  5. -> m a
#

Create and use a temporary directory.

Creates a new temporary directory inside the given directory, making use of the template. The temp directory is deleted after use. For example:

withTempDirectory "src" "sdist." $ \tmpDir -> do ...

The tmpDir will be a new subdirectory of the given directory, e.g. src/sdist.342.

valuewithTempFile
  1. :: MonadUnliftIO m
  2. => FilePath

    Temp dir to create the file in.

  3. -> String

    File name template. See openTempFile.

  4. -> (FilePath -> Handle -> m a)

    Callback that can use the file.

  5. -> m a
#

Use a temporary filename that doesn't already exist.

Creates a new temporary file inside the given directory, making use of the template. The temp file is deleted after use. For example:

withTempFile "src" "sdist." $ \tmpFile hFile -> do ...

The tmpFile will be file in the given directory, e.g. src/sdist.342.

valuereadFileUtf8 :: MonadIO m => FilePath -> m Text
#

Read a file in UTF8 encoding, throwing an exception on invalid character encoding.

This function will use OS-specific line ending handling.

Exit

4 declarations
valueexitFailure :: MonadIO m => m a
#

Lifted version of "System.Exit.exitFailure".

@since 0.1.9.0.

valueexitSuccess :: MonadIO m => m a
#

Lifted version of "System.Exit.exitSuccess".

@since 0.1.9.0.

datadata ExitCode
#

Defines the exit codes that a program can return.

Constructors

  • ExitSuccess

    indicates successful termination;

  • ExitFailure Int

    indicates program failure with an exit code. The exact interpretation of the code is operating-system dependent. In particular, some values may be prohibited (e.g. 0 on a POSIX-compliant system).

Instances8Eq, Ord, Read, Show, Generic, Exception, …

Mutable Variables

0 declarations

SomeRef

datadata SomeRef a
#

Abstraction over how to read from and write to a mutable reference

Instances2HasStateRef, HasWriteRef
  • HasStateRef a (SomeRef a)Defined in rio-0.1.22.0 · RIO.Prelude.RIO

    Identity state reference where the SomeRef is the env

  • HasWriteRef a (SomeRef a)Defined in rio-0.1.22.0 · RIO.Prelude.RIO

    Identity write reference where the SomeRef is the env

valuemapRIO :: (outer -> inner) -> RIO inner a -> RIO outer a
#

Lift one RIO env to another.

classclass HasStateRef s env | env -> s where
#

Environment values with stateful capabilities to SomeRef

Methods

Instances1HasStateRef
  • HasStateRef a (SomeRef a)Defined in rio-0.1.22.0 · RIO.Prelude.RIO

    Identity state reference where the SomeRef is the env

classclass HasWriteRef w env | env -> w where
#

Environment values with writing capabilities to SomeRef

Methods

Instances1HasWriteRef
  • HasWriteRef a (SomeRef a)Defined in rio-0.1.22.0 · RIO.Prelude.RIO

    Identity write reference where the SomeRef is the env

valuemodifySomeRef :: MonadIO m => SomeRef a -> (a -> a) -> m ()
#

Modify a SomeRef This function is subject to change due to the lack of atomic operations

URef

newtypenewtype URef s a
#

An unboxed reference. This works like an IORef, but the data is stored in a bytearray instead of a heap object, avoiding significant allocation overhead in some cases. For a concrete example, see this Stack Overflow question: https://stackoverflow.com/questions/27261813/why-is-my-little-stref-int-require-allocating-gigabytes.

The first parameter is the state token type, the same as would be used for the ST monad. If you're using an IO-based monad, you can use the convenience IOURef type synonym instead.

IORef

newtypenewtype IORef a
#

A mutable variable in the IO monad.

Example11 expressions
import GHC.Internal.Data.IORefr <- newIORef 0readIORef r0writeIORef r 1readIORef r1atomicWriteIORef r 2readIORef r2modifyIORef' r (+ 1)readIORef r3atomicModifyIORef' r (\a -> (a + 1, ()))readIORef r4

See also STRef and Control.Concurrent.MVar.MVar.

Instances3NFData1, Eq, NFData
  • NFData1 IORefDefined in deepseq-1.5.0.0 · Control.DeepSeq
  • Eq (IORef a)Defined in ghc-internal-9.1003.0 · GHC.Internal.IORef

    Pointer equality.

  • NFData (IORef a)Defined in deepseq-1.5.0.0 · Control.DeepSeq

    NOTE: Only strict in the reference and not the referenced value.

MVar

datadata MVar a
#

An MVar (pronounced "em-var") is a synchronising variable, used for communication between concurrent threads. It can be thought of as a box, which may be empty or full.

Instances3NFData1, Eq, NFData
  • NFData1 MVarDefined in deepseq-1.5.0.0 · Control.DeepSeq
  • Eq (MVar a)Defined in ghc-internal-9.1003.0 · GHC.Internal.MVar

    Compares the underlying pointers.

  • NFData (MVar a)Defined in deepseq-1.5.0.0 · Control.DeepSeq

    NOTE: Only strict in the reference and not the referenced value.

QSem

newtypenewtype QSem
#

QSem is a quantity semaphore in which the resource is acquired and released in units of one. It provides guaranteed FIFO ordering for satisfying blocked waitQSem calls.

The pattern

bracket_ waitQSem signalQSem (...)

is safe; it never loses a unit of the resource.

valuewithQSem :: MonadUnliftIO m => QSem -> m a -> m a
#

withQSem is an exception-safe wrapper for performing the provided operation while holding a unit of value from the semaphore. It ensures the semaphore cannot be leaked if there are exceptions.

QSemN

datadata QSemN
#

QSemN is a quantity semaphore in which the resource is acquired and released in arbitrary amounts. It provides guaranteed FIFO ordering for satisfying blocked waitQSemN calls.

The pattern

bracket_ (waitQSemN n) (signalQSemN n) (...)

is safe; it never loses any of the resource.

valuewithQSemN :: MonadUnliftIO m => QSemN -> Int -> m a -> m a
#

withQSemN is an exception-safe wrapper for performing the provided operation while holding N unit of value from the semaphore. It ensures the semaphore cannot be leaked if there are exceptions.

Memoize

newtypenewtype Memoized a
#

A "run once" value, with results saved. Extract the value with runMemoized. For single-threaded usage, you can use memoizeRef to create a value. If you need guarantees that only one thread will run the action at a time, use memoizeMVar.

Note that this type provides a Show instance for convenience, but not useful information can be provided.

Instances4Monad, Functor, Applicative, Show
valuememoizeRef :: MonadUnliftIO m => m a -> m (Memoized a)
#

Create a new Memoized value using an IORef under the surface. Note that the action may be run in multiple threads simultaneously, so this may not be thread safe (depending on the underlying action). Consider using memoizeMVar.

Deque

module RIO.Deque

Debugging

27 declarations
valuetrace :: Text -> a -> a
#

Trace statement left in code

valuetraceShow :: Show a => a -> b -> b
#

Trace statement left in code