-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | An easy to use, performant extensible effects library. -- -- An easy to use, performant extensible effects library with seamless -- integration with the existing Haskell ecosystem. . This is the -- "batteries-included" variant. See the effectful-core -- package if you need a more limited dependency footprint or want to -- browse documentation of core modules. @package effectful @version 2.3.1.0 -- | Lifted Control.Concurrent.Chan. module Effectful.Concurrent.Chan -- | 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 qualified Effectful.Reader.Static 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 qualified Effectful.State.Static.Local as SL
--
-- >>> :{
-- runEff . SL.execState "Hi" . runConcurrent $ do
-- replicateConcurrently_ 3 $ SL.modify (++ "!")
-- :}
-- "Hi"
--
--
--
-- >>> 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.
data Concurrent :: Effect
-- | Run the Concurrent effect.
runConcurrent :: IOE :> es => Eff (Concurrent : es) a -> Eff es a
-- | Chan is an abstract type representing an unbounded FIFO
-- channel.
data () => Chan a
-- | Lifted newChan.
newChan :: Concurrent :> es => Eff es (Chan a)
-- | Lifted writeChan.
writeChan :: Concurrent :> es => Chan a -> a -> Eff es ()
-- | Lifted readChan.
readChan :: Concurrent :> es => Chan a -> Eff es a
-- | Lifted dupChan.
dupChan :: Concurrent :> es => Chan a -> Eff es (Chan a)
-- | Lifted getChanContents.
getChanContents :: Concurrent :> es => Chan a -> Eff es [a]
-- | Lifted writeList2Chan.
writeList2Chan :: Concurrent :> es => Chan a -> [a] -> Eff es ()
-- | Lifted Control.Concurrent.Async.
module Effectful.Concurrent.Async
-- | 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 qualified Effectful.Reader.Static 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 qualified Effectful.State.Static.Local as SL
--
-- >>> :{
-- runEff . SL.execState "Hi" . runConcurrent $ do
-- replicateConcurrently_ 3 $ SL.modify (++ "!")
-- :}
-- "Hi"
--
--
--
-- >>> 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.
data Concurrent :: Effect
-- | Run the Concurrent effect.
runConcurrent :: IOE :> es => Eff (Concurrent : es) a -> Eff es 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).
data () => Async a
-- | Lifted withAsync.
withAsync :: Concurrent :> es => Eff es a -> (Async a -> Eff es b) -> Eff es b
-- | Lifted withAsyncBound.
withAsyncBound :: Concurrent :> es => Eff es a -> (Async a -> Eff es b) -> Eff es b
-- | Lifted withAsyncOn.
withAsyncOn :: Concurrent :> es => Int -> Eff es a -> (Async a -> Eff es b) -> Eff es b
-- | Lifted withAsyncWithUnmask.
withAsyncWithUnmask :: Concurrent :> es => ((forall c. Eff es c -> Eff es c) -> Eff es a) -> (Async a -> Eff es b) -> Eff es b
-- | Lifted withAsyncOnWithUnmask.
withAsyncOnWithUnmask :: Concurrent :> es => Int -> ((forall c. Eff es c -> Eff es c) -> Eff es a) -> (Async a -> Eff es b) -> Eff es b
-- | Lifted wait.
wait :: Concurrent :> es => Async a -> Eff es a
-- | Lifted poll.
poll :: Concurrent :> es => Async a -> Eff es (Maybe (Either SomeException a))
-- | Lifted waitCatch.
waitCatch :: Concurrent :> es => Async a -> Eff es (Either SomeException a)
-- | Returns the ThreadId of the thread running the given
-- Async.
asyncThreadId :: Async a -> ThreadId
-- | Lifted cancel.
cancel :: Concurrent :> es => Async a -> Eff es ()
-- | Lifted uninterruptibleCancel.
uninterruptibleCancel :: Concurrent :> es => Async a -> Eff es ()
-- | Lifted cancelWith.
cancelWith :: (Exception e, Concurrent :> es) => Async a -> e -> Eff es ()
-- | The exception thrown by cancel to terminate a thread.
data () => AsyncCancelled
AsyncCancelled :: AsyncCancelled
-- | Compare two Asyncs that may have different types by their
-- ThreadId.
compareAsyncs :: Async a -> Async b -> Ordering
-- | Lifted race.
race :: Concurrent :> es => Eff es a -> Eff es b -> Eff es (Either a b)
-- | Lifted race_.
race_ :: Concurrent :> es => Eff es a -> Eff es b -> Eff es ()
-- | Lifted concurrently.
concurrently :: Concurrent :> es => Eff es a -> Eff es b -> Eff es (a, b)
-- | Lifted concurrently_.
concurrently_ :: Concurrent :> es => Eff es a -> Eff es b -> Eff es ()
-- | Lifted mapConcurrently.
mapConcurrently :: (Traversable f, Concurrent :> es) => (a -> Eff es b) -> f a -> Eff es (f b)
-- | Lifted forConcurrently.
forConcurrently :: (Traversable f, Concurrent :> es) => f a -> (a -> Eff es b) -> Eff es (f b)
-- | Lifted mapConcurrently_.
mapConcurrently_ :: (Foldable f, Concurrent :> es) => (a -> Eff es b) -> f a -> Eff es ()
-- | Lifted forConcurrently_.
forConcurrently_ :: (Foldable f, Concurrent :> es) => f a -> (a -> Eff es b) -> Eff es ()
-- | Lifted replicateConcurrently.
replicateConcurrently :: Concurrent :> es => Int -> Eff es a -> Eff es [a]
-- | Lifted replicateConcurrently_.
replicateConcurrently_ :: Concurrent :> es => Int -> Eff es a -> Eff es ()
-- | Lifted Concurrently.
newtype Concurrently es a
Concurrently :: Eff es a -> Concurrently es a
[runConcurrently] :: Concurrently es a -> Eff es a
-- | Lifted Conc.
data Conc :: [Effect] -> Type -> Type
-- | Lifted conc.
conc :: Eff es a -> Conc es a
-- | Lifted runConc.
runConc :: Concurrent :> es => Conc es a -> Eff es a
-- | Things that can go wrong in the structure of a Conc. These are
-- programmer errors.
data () => ConcException
EmptyWithNoAlternative :: ConcException
-- | Lifted pooledMapConcurrentlyN.
pooledMapConcurrentlyN :: (Concurrent :> es, Traversable t) => Int -> (a -> Eff es b) -> t a -> Eff es (t b)
-- | Lifted pooledMapConcurrently.
pooledMapConcurrently :: (Concurrent :> es, Traversable t) => (a -> Eff es b) -> t a -> Eff es (t b)
-- | Lifted pooledMapConcurrentlyN.
pooledMapConcurrentlyN_ :: (Concurrent :> es, Foldable f) => Int -> (a -> Eff es b) -> f a -> Eff es ()
-- | Lifted pooledMapConcurrently_.
pooledMapConcurrently_ :: (Concurrent :> es, Foldable f) => (a -> Eff es b) -> f a -> Eff es ()
-- | Lifted pooledForConcurrentlyN.
pooledForConcurrentlyN :: (Concurrent :> es, Traversable t) => Int -> t a -> (a -> Eff es b) -> Eff es (t b)
-- | Lifted pooledForConcurrently.
pooledForConcurrently :: (Concurrent :> es, Traversable t) => t a -> (a -> Eff es b) -> Eff es (t b)
-- | Lifted pooledForConcurrentlyN.
pooledForConcurrentlyN_ :: (Concurrent :> es, Foldable f) => Int -> f a -> (a -> Eff es b) -> Eff es ()
-- | Lifted pooledForConcurrently_.
pooledForConcurrently_ :: (Concurrent :> es, Foldable f) => f a -> (a -> Eff es b) -> Eff es ()
-- | Lifted pooledReplicateConcurrentlyN.
pooledReplicateConcurrentlyN :: Concurrent :> es => Int -> Int -> Eff es a -> Eff es [a]
-- | Lifted pooledReplicateConcurrently.
pooledReplicateConcurrently :: Concurrent :> es => Int -> Eff es a -> Eff es [a]
-- | Lifted pooledReplicateConcurrentlyN_.
pooledReplicateConcurrentlyN_ :: Concurrent :> es => Int -> Int -> Eff es a -> Eff es ()
-- | Lifted pooledReplicateConcurrently_.
pooledReplicateConcurrently_ :: Concurrent :> es => Int -> Eff es a -> Eff es ()
-- | A version of wait that can be used inside an STM transaction.
waitSTM :: Async a -> STM a
-- | A version of poll that can be used inside an STM transaction.
pollSTM :: Async a -> STM (Maybe (Either SomeException a))
-- | A version of waitCatch that can be used inside an STM
-- transaction.
waitCatchSTM :: Async a -> STM (Either SomeException a)
-- | Lifted waitAny.
waitAny :: Concurrent :> es => [Async a] -> Eff es (Async a, a)
-- | Lifted waitAnyCatch.
waitAnyCatch :: Concurrent :> es => [Async a] -> Eff es (Async a, Either SomeException a)
-- | Lifted waitAnyCancel.
waitAnyCancel :: Concurrent :> es => [Async a] -> Eff es (Async a, a)
-- | Lifted waitAnyCatchCancel.
waitAnyCatchCancel :: Concurrent :> es => [Async a] -> Eff es (Async a, Either SomeException a)
-- | Lifted waitEither.
waitEither :: Concurrent :> es => Async a -> Async b -> Eff es (Either a b)
-- | Lifted waitEitherCatch.
waitEitherCatch :: Concurrent :> es => Async a -> Async b -> Eff es (Either (Either SomeException a) (Either SomeException b))
-- | Lifted waitEitherCancel.
waitEitherCancel :: Concurrent :> es => Async a -> Async b -> Eff es (Either a b)
-- | Lifted waitEitherCatchCancel.
waitEitherCatchCancel :: Concurrent :> es => Async a -> Async b -> Eff es (Either (Either SomeException a) (Either SomeException b))
-- | Lifted waitEither_.
waitEither_ :: Concurrent :> es => Async a -> Async b -> Eff es ()
-- | Lifted waitBoth.
waitBoth :: Concurrent :> es => Async a -> Async b -> Eff es (a, b)
-- | A version of waitAny that can be used inside an STM
-- transaction.
waitAnySTM :: [Async a] -> STM (Async a, a)
-- | A version of waitAnyCatch that can be used inside an STM
-- transaction.
waitAnyCatchSTM :: [Async a] -> STM (Async a, Either SomeException a)
-- | A version of waitEither that can be used inside an STM
-- transaction.
waitEitherSTM :: Async a -> Async b -> STM (Either a b)
-- | A version of waitEitherCatch that can be used inside an STM
-- transaction.
waitEitherCatchSTM :: Async a -> Async b -> STM (Either (Either SomeException a) (Either SomeException b))
-- | A version of waitEither_ that can be used inside an STM
-- transaction.
waitEitherSTM_ :: Async a -> Async b -> STM ()
-- | A version of waitBoth that can be used inside an STM
-- transaction.
waitBothSTM :: Async a -> Async b -> STM (a, b)
-- | Lifted async.
async :: Concurrent :> es => Eff es a -> Eff es (Async a)
-- | Lifted asyncBound.
asyncBound :: Concurrent :> es => Eff es a -> Eff es (Async a)
-- | Lifted asyncOn.
asyncOn :: Concurrent :> es => Int -> Eff es a -> Eff es (Async a)
-- | Lifted asyncWithUnmask.
asyncWithUnmask :: Concurrent :> es => ((forall b. Eff es b -> Eff es b) -> Eff es a) -> Eff es (Async a)
-- | Lifted asyncOnWithUnmask.
asyncOnWithUnmask :: Concurrent :> es => Int -> ((forall b. Eff es b -> Eff es b) -> Eff es a) -> Eff es (Async a)
-- | Lifted link.
link :: Concurrent :> es => Async a -> Eff es ()
-- | Lifted linkOnly.
linkOnly :: Concurrent :> es => (SomeException -> Bool) -> Async a -> Eff es ()
-- | Lifted link2.
link2 :: Concurrent :> es => Async a -> Async b -> Eff es ()
-- | Lifted link2Only.
link2Only :: Concurrent :> es => (SomeException -> Bool) -> Async a -> Async b -> Eff es ()
data () => ExceptionInLinkedThread
ExceptionInLinkedThread :: Async a -> SomeException -> ExceptionInLinkedThread
instance GHC.Base.Functor (Effectful.Concurrent.Async.Conc es)
instance GHC.Base.Functor (Effectful.Concurrent.Async.Concurrently es)
instance (Effectful.Concurrent.Effect.Concurrent Effectful.Internal.Effect.:> es) => GHC.Base.Applicative (Effectful.Concurrent.Async.Concurrently es)
instance (Effectful.Concurrent.Effect.Concurrent Effectful.Internal.Effect.:> es) => GHC.Base.Alternative (Effectful.Concurrent.Async.Concurrently es)
instance (Effectful.Concurrent.Effect.Concurrent Effectful.Internal.Effect.:> es, GHC.Base.Semigroup a) => GHC.Base.Semigroup (Effectful.Concurrent.Async.Concurrently es a)
instance (Effectful.Concurrent.Effect.Concurrent Effectful.Internal.Effect.:> es, GHC.Base.Monoid a) => GHC.Base.Monoid (Effectful.Concurrent.Async.Concurrently es a)
instance GHC.Base.Applicative (Effectful.Concurrent.Async.Conc es)
instance GHC.Base.Alternative (Effectful.Concurrent.Async.Conc es)
instance GHC.Base.Semigroup a => GHC.Base.Semigroup (Effectful.Concurrent.Async.Conc es a)
instance GHC.Base.Monoid a => GHC.Base.Monoid (Effectful.Concurrent.Async.Conc es a)
-- | Lifted Control.Concurrent.
--
-- For functions that spawn threads, the order of preference for their
-- usage is recommended as follows:
--
-- 1) High level functions from Effectful.Concurrent.Async such as
-- withAsync, concurrently or mapConcurrently.
--
-- 2) Low level functions from Effectful.Concurrent.Async such as
-- async.
--
-- 3) Low level functions from Effectful.Concurrent such as
-- forkIO.
module Effectful.Concurrent
-- | 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 qualified Effectful.Reader.Static 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 qualified Effectful.State.Static.Local as SL
--
-- >>> :{
-- runEff . SL.execState "Hi" . runConcurrent $ do
-- replicateConcurrently_ 3 $ SL.modify (++ "!")
-- :}
-- "Hi"
--
--
--
-- >>> 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.
data Concurrent :: Effect
-- | Run the Concurrent effect.
runConcurrent :: IOE :> es => Eff (Concurrent : es) a -> Eff es a
-- | Lifted myThreadId.
myThreadId :: Concurrent :> es => Eff es ThreadId
-- | Lifted forkIO.
forkIO :: Concurrent :> es => Eff es () -> Eff es ThreadId
-- | Lifted forkFinally.
forkFinally :: Concurrent :> es => Eff es a -> (Either SomeException a -> Eff es ()) -> Eff es ThreadId
-- | Lifted forkIOWithUnmask.
forkIOWithUnmask :: Concurrent :> es => ((forall a. Eff es a -> Eff es a) -> Eff es ()) -> Eff es ThreadId
-- | Lifted killThread.
killThread :: Concurrent :> es => ThreadId -> Eff es ()
-- | Lifted throwTo.
throwTo :: (Concurrent :> es, Exception e) => ThreadId -> e -> Eff es ()
-- | Lifted forkOn.
forkOn :: Concurrent :> es => Int -> Eff es () -> Eff es ThreadId
-- | Lifted forkOnWithUnmask.
forkOnWithUnmask :: Concurrent :> es => Int -> ((forall a. Eff es a -> Eff es a) -> Eff es ()) -> Eff es ThreadId
-- | Lifted getNumCapabilities.
getNumCapabilities :: Concurrent :> es => Eff es Int
-- | Lifted setNumCapabilities.
setNumCapabilities :: Concurrent :> es => Int -> Eff es ()
-- | Lifted getNumProcessors.
getNumProcessors :: Concurrent :> es => Eff es Int
-- | Lifted threadCapability.
threadCapability :: Concurrent :> es => ThreadId -> Eff es (Int, Bool)
-- | Lifted yield.
yield :: Concurrent :> es => Eff es ()
-- | Lifted threadDelay.
threadDelay :: Concurrent :> es => Int -> Eff es ()
-- | Lifted threadWaitRead.
threadWaitRead :: Concurrent :> es => Fd -> Eff es ()
-- | Lifted threadWaitWrite.
threadWaitWrite :: Concurrent :> es => Fd -> Eff es ()
-- | Lifted threadWaitReadSTM.
threadWaitReadSTM :: Concurrent :> es => Fd -> Eff es (STM (), Eff es ())
-- | Lifted threadWaitWriteSTM.
threadWaitWriteSTM :: Concurrent :> es => Fd -> Eff es (STM (), Eff es ())
-- | Lifted forkOS.
forkOS :: Concurrent :> es => Eff es () -> Eff es ThreadId
-- | Lifted forkOSWithUnmask.
forkOSWithUnmask :: Concurrent :> es => ((forall a. Eff es a -> Eff es a) -> Eff es ()) -> Eff es ThreadId
-- | Lifted isCurrentThreadBound.
isCurrentThreadBound :: Concurrent :> es => Eff es Bool
-- | Lifted runInBoundThread.
runInBoundThread :: Concurrent :> es => Eff es a -> Eff es a
-- | Lifted runInUnboundThread.
runInUnboundThread :: Concurrent :> es => Eff es a -> Eff es a
-- | Lifted mkWeakThreadId.
mkWeakThreadId :: Concurrent :> es => ThreadId -> Eff es (Weak ThreadId)
-- | True if bound threads are supported. If
-- rtsSupportsBoundThreads is False,
-- isCurrentThreadBound will always return False and both
-- forkOS and runInBoundThread will fail.
rtsSupportsBoundThreads :: Bool
-- | Lifted Control.Concurrent.MVar.
module Effectful.Concurrent.MVar
-- | 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 qualified Effectful.Reader.Static 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 qualified Effectful.State.Static.Local as SL
--
-- >>> :{
-- runEff . SL.execState "Hi" . runConcurrent $ do
-- replicateConcurrently_ 3 $ SL.modify (++ "!")
-- :}
-- "Hi"
--
--
--
-- >>> 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.
data Concurrent :: Effect
-- | Run the Concurrent effect.
runConcurrent :: IOE :> es => Eff (Concurrent : es) a -> Eff es 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.
data () => MVar a
-- | Lifted newEmptyMVar.
newEmptyMVar :: Concurrent :> es => Eff es (MVar a)
-- | Lifted newMVar.
newMVar :: Concurrent :> es => a -> Eff es (MVar a)
-- | Lifted takeMVar.
takeMVar :: Concurrent :> es => MVar a -> Eff es a
-- | Lifted putMVar.
putMVar :: Concurrent :> es => MVar a -> a -> Eff es ()
-- | Lifted readMVar.
readMVar :: Concurrent :> es => MVar a -> Eff es a
-- | Lifted swapMVar.
swapMVar :: Concurrent :> es => MVar a -> a -> Eff es a
-- | Lifted tryTakeMVar.
tryTakeMVar :: Concurrent :> es => MVar a -> Eff es (Maybe a)
-- | Lifted tryPutMVar.
tryPutMVar :: Concurrent :> es => MVar a -> a -> Eff es Bool
-- | Lifted isEmptyMVar.
isEmptyMVar :: Concurrent :> es => MVar a -> Eff es Bool
-- | Lifted withMVar.
withMVar :: Concurrent :> es => MVar a -> (a -> Eff es b) -> Eff es b
-- | Lifted withMVarMasked.
withMVarMasked :: Concurrent :> es => MVar a -> (a -> Eff es b) -> Eff es b
-- | Lifted modifyMVar.
modifyMVar :: Concurrent :> es => MVar a -> (a -> Eff es (a, b)) -> Eff es b
-- | Lifted modifyMVar_.
modifyMVar_ :: Concurrent :> es => MVar a -> (a -> Eff es a) -> Eff es ()
-- | Lifted modifyMVarMasked.
modifyMVarMasked :: Concurrent :> es => MVar a -> (a -> Eff es (a, b)) -> Eff es b
-- | Lifted modifyMVarMasked_.
modifyMVarMasked_ :: Concurrent :> es => MVar a -> (a -> Eff es a) -> Eff es ()
-- | Lifted tryReadMVar.
tryReadMVar :: Concurrent :> es => MVar a -> Eff es (Maybe a)
-- | Lifted mkWeakMVar.
mkWeakMVar :: Concurrent :> es => MVar a -> Eff es () -> Eff es (Weak (MVar a))
-- | Lifted Control.Concurrent.MVar with operations that force
-- values put inside an MVar to WHNF.
module Effectful.Concurrent.MVar.Strict
-- | 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 qualified Effectful.Reader.Static 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 qualified Effectful.State.Static.Local as SL
--
-- >>> :{
-- runEff . SL.execState "Hi" . runConcurrent $ do
-- replicateConcurrently_ 3 $ SL.modify (++ "!")
-- :}
-- "Hi"
--
--
--
-- >>> 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.
data Concurrent :: Effect
-- | Run the Concurrent effect.
runConcurrent :: IOE :> es => Eff (Concurrent : es) a -> Eff es 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.
data () => MVar a
-- | Lifted newEmptyMVar.
newEmptyMVar :: Concurrent :> es => Eff es (MVar a)
-- | Lifted newMVar that evaluates the value to WHNF.
newMVar :: Concurrent :> es => a -> Eff es (MVar a)
-- | Lifted takeMVar.
takeMVar :: Concurrent :> es => MVar a -> Eff es a
-- | Lifted putMVar.
putMVar :: Concurrent :> es => MVar a -> a -> Eff es ()
-- | Lifted readMVar.
readMVar :: Concurrent :> es => MVar a -> Eff es a
-- | Lifted swapMVar that evaluates the new value to WHNF.
swapMVar :: Concurrent :> es => MVar a -> a -> Eff es a
-- | Lifted tryTakeMVar.
tryTakeMVar :: Concurrent :> es => MVar a -> Eff es (Maybe a)
-- | Lifted tryPutMVar that evaluates the new value to WHNF.
tryPutMVar :: Concurrent :> es => MVar a -> a -> Eff es Bool
-- | Lifted isEmptyMVar.
isEmptyMVar :: Concurrent :> es => MVar a -> Eff es Bool
-- | Lifted withMVar.
withMVar :: Concurrent :> es => MVar a -> (a -> Eff es b) -> Eff es b
-- | Lifted withMVarMasked.
withMVarMasked :: Concurrent :> es => MVar a -> (a -> Eff es b) -> Eff es b
-- | Lifted modifyMVar that evaluates the new value to WHNF.
modifyMVar :: Concurrent :> es => MVar a -> (a -> Eff es (a, b)) -> Eff es b
-- | Lifted modifyMVar_ that evaluates the new value to WHNF.
modifyMVar_ :: Concurrent :> es => MVar a -> (a -> Eff es a) -> Eff es ()
-- | Lifted modifyMVarMasked that evaluates the new value to WHNF.
modifyMVarMasked :: Concurrent :> es => MVar a -> (a -> Eff es (a, b)) -> Eff es b
-- | Lifted modifyMVarMasked_ that evaluates the new value to WHNF.
modifyMVarMasked_ :: Concurrent :> es => MVar a -> (a -> Eff es a) -> Eff es ()
-- | Lifted tryReadMVar.
tryReadMVar :: Concurrent :> es => MVar a -> Eff es (Maybe a)
-- | Lifted mkWeakMVar.
mkWeakMVar :: Concurrent :> es => MVar a -> Eff es () -> Eff es (Weak (MVar a))
-- | Lifted Control.Concurrent.QSem.
module Effectful.Concurrent.QSem
-- | 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 qualified Effectful.Reader.Static 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 qualified Effectful.State.Static.Local as SL
--
-- >>> :{
-- runEff . SL.execState "Hi" . runConcurrent $ do
-- replicateConcurrently_ 3 $ SL.modify (++ "!")
-- :}
-- "Hi"
--
--
--
-- >>> 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.
data Concurrent :: Effect
-- | Run the Concurrent effect.
runConcurrent :: IOE :> es => Eff (Concurrent : es) a -> Eff es a
-- | 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. data () => QSem -- | Lifted newQSem. newQSem :: Concurrent :> es => Int -> Eff es QSem -- | Lifted waitQSem. waitQSem :: Concurrent :> es => QSem -> Eff es () -- | Lifted signalQSem. signalQSem :: Concurrent :> es => QSem -> Eff es () -- | Lifted Control.Concurrent.QSemN. module Effectful.Concurrent.QSemN -- | 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 qualified Effectful.Reader.Static 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 qualified Effectful.State.Static.Local as SL
--
-- >>> :{
-- runEff . SL.execState "Hi" . runConcurrent $ do
-- replicateConcurrently_ 3 $ SL.modify (++ "!")
-- :}
-- "Hi"
--
--
--
-- >>> 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.
data Concurrent :: Effect
-- | Run the Concurrent effect.
runConcurrent :: IOE :> es => Eff (Concurrent : es) a -> Eff es a
-- | QSemN is a quantity semaphore in which the resource is acquired
-- and released in units of one. 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. data () => QSemN -- | Lifted newQSemN. newQSemN :: Concurrent :> es => Int -> Eff es QSemN -- | Lifted waitQSemN. waitQSemN :: Concurrent :> es => QSemN -> Int -> Eff es () -- | Lifted signalQSemN. signalQSemN :: Concurrent :> es => QSemN -> Int -> Eff es () -- | Lifted Control.Concurrent.STM. module Effectful.Concurrent.STM -- | 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 qualified Effectful.Reader.Static 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 qualified Effectful.State.Static.Local as SL
--
-- >>> :{
-- runEff . SL.execState "Hi" . runConcurrent $ do
-- replicateConcurrently_ 3 $ SL.modify (++ "!")
-- :}
-- "Hi"
--
--
--
-- >>> 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.
data Concurrent :: Effect
-- | Run the Concurrent effect.
runConcurrent :: IOE :> es => Eff (Concurrent : es) a -> Eff es a
-- | A monad supporting atomic memory transactions.
data () => STM a
-- | Lifted atomically.
atomically :: Concurrent :> es => STM a -> Eff es 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)
retry :: 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.
orElse :: STM a -> STM a -> STM a
-- | Check that the boolean condition is true and, if not, retry.
--
-- In other words, check b = unless b retry.
check :: Bool -> STM ()
-- | 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. throwSTM :: Exception e => e -> 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. catchSTM :: Exception e => STM a -> (e -> STM a) -> STM a -- | Shared memory locations that support atomic memory transactions. data () => TVar a -- | Lifted newTVarIO. newTVarIO :: Concurrent :> es => a -> Eff es (TVar a) -- | Lifted readTVarIO. readTVarIO :: Concurrent :> es => TVar a -> Eff es a -- | Create a new TVar holding a value supplied newTVar :: a -> STM (TVar a) -- | Return the current value stored in a TVar. readTVar :: TVar a -> STM a -- | Write the supplied value into a TVar. writeTVar :: TVar a -> a -> STM () -- | Mutate the contents of a TVar. N.B., this version is -- non-strict. modifyTVar :: TVar a -> (a -> a) -> STM () -- | Strict version of modifyTVar. modifyTVar' :: TVar a -> (a -> a) -> STM () -- | Swap the contents of a TVar for a new value. swapTVar :: TVar a -> a -> STM a -- | Lifted registerDelay. registerDelay :: Concurrent :> es => Int -> Eff es (TVar Bool) -- | Lifted mkWeakTVar. mkWeakTVar :: Concurrent :> es => TVar a -> Eff es () -> Eff es (Weak (TVar 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. data () => TMVar a -- | Create a TMVar which contains the supplied value. newTMVar :: a -> STM (TMVar a) -- | Create a TMVar which is initially empty. newEmptyTMVar :: STM (TMVar a) -- | Lifted newTMVarIO. newTMVarIO :: Concurrent :> es => a -> Eff es (TMVar a) -- | Lifted newEmptyTMVarIO. newEmptyTMVarIO :: Concurrent :> es => Eff es (TMVar a) -- | Return the contents of the TMVar. If the TMVar is -- currently empty, the transaction will retry. After a -- takeTMVar, the TMVar is left empty. takeTMVar :: TMVar a -> STM a -- | Put a value into a TMVar. If the TMVar is currently -- full, putTMVar will retry. putTMVar :: TMVar a -> a -> STM () -- | This is a combination of takeTMVar and putTMVar; ie. it -- takes the value from the TMVar, puts it back, and also returns -- it. readTMVar :: TMVar a -> STM a -- | A version of readTMVar which does not retry. Instead it returns -- Nothing if no value is available. tryReadTMVar :: TMVar a -> STM (Maybe a) -- | Swap the contents of a TMVar for a new value. swapTMVar :: TMVar a -> a -> STM a -- | A version of takeTMVar that does not retry. The -- tryTakeTMVar function returns Nothing if the -- TMVar was empty, or Just a if the TMVar -- was full with contents a. After tryTakeTMVar, the -- TMVar is left empty. tryTakeTMVar :: TMVar a -> STM (Maybe a) -- | A version of putTMVar that does not retry. The -- tryPutTMVar function attempts to put the value a into -- the TMVar, returning True if it was successful, or -- False otherwise. tryPutTMVar :: TMVar a -> a -> STM Bool -- | Check whether a given TMVar is empty. isEmptyTMVar :: TMVar a -> STM Bool -- | Lifted mkWeakTMVar. mkWeakTMVar :: Concurrent :> es => TMVar a -> Eff es () -> Eff es (Weak (TMVar a)) -- | TChan is an abstract type representing an unbounded FIFO -- channel. data () => TChan a -- | Build and return a new instance of TChan newTChan :: STM (TChan a) -- | Lifted newTChanIO. newTChanIO :: Concurrent :> es => Eff es (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. newBroadcastTChan :: STM (TChan a) -- | Lifted newBroadcastTChanIO. newBroadcastTChanIO :: Concurrent :> es => Eff es (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. dupTChan :: 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. cloneTChan :: TChan a -> STM (TChan a) -- | Read the next value from the TChan. readTChan :: TChan a -> STM a -- | A version of readTChan which does not retry. Instead it returns -- Nothing if no value is available. tryReadTChan :: TChan a -> STM (Maybe a) -- | Get the next value from the TChan without removing it, -- retrying if the channel is empty. peekTChan :: TChan a -> STM a -- | A version of peekTChan which does not retry. Instead it returns -- Nothing if no value is available. tryPeekTChan :: TChan a -> STM (Maybe a) -- | Write a value to a TChan. writeTChan :: TChan a -> a -> STM () -- | Put a data item back onto a channel, where it will be the next item -- read. unGetTChan :: TChan a -> a -> STM () -- | Returns True if the supplied TChan is empty. isEmptyTChan :: TChan a -> STM Bool -- | TQueue is an abstract type representing an unbounded FIFO -- channel. data () => TQueue a -- | Build and returns a new instance of TQueue newTQueue :: STM (TQueue a) -- | Lifted newTQueueIO. newTQueueIO :: Concurrent :> es => Eff es (TQueue a) -- | Read the next value from the TQueue. readTQueue :: TQueue a -> STM a -- | A version of readTQueue which does not retry. Instead it -- returns Nothing if no value is available. tryReadTQueue :: TQueue a -> STM (Maybe a) -- | Get the next value from the TQueue without removing it, -- retrying if the channel is empty. peekTQueue :: TQueue a -> STM a -- | A version of peekTQueue which does not retry. Instead it -- returns Nothing if no value is available. tryPeekTQueue :: TQueue a -> STM (Maybe a) -- | Efficiently read the entire contents of a TQueue into a list. -- This function never retries. flushTQueue :: TQueue a -> STM [a] -- | Write a value to a TQueue. writeTQueue :: TQueue a -> a -> STM () -- | Put a data item back onto a channel, where it will be the next item -- read. unGetTQueue :: TQueue a -> a -> STM () -- | Returns True if the supplied TQueue is empty. isEmptyTQueue :: TQueue a -> STM Bool -- | TBQueue is an abstract type representing a bounded FIFO -- channel. data () => TBQueue a -- | Builds and returns a new instance of TBQueue. newTBQueue :: Natural -> STM (TBQueue a) -- | Lifted newTBQueueIO. newTBQueueIO :: Concurrent :> es => Natural -> Eff es (TBQueue a) -- | Read the next value from the TBQueue. readTBQueue :: TBQueue a -> STM a -- | A version of readTBQueue which does not retry. Instead it -- returns Nothing if no value is available. tryReadTBQueue :: TBQueue a -> STM (Maybe a) -- | Get the next value from the TBQueue without removing it, -- retrying if the channel is empty. peekTBQueue :: TBQueue a -> STM a -- | A version of peekTBQueue which does not retry. Instead it -- returns Nothing if no value is available. tryPeekTBQueue :: TBQueue a -> STM (Maybe a) -- | Efficiently read the entire contents of a TBQueue into a list. -- This function never retries. flushTBQueue :: TBQueue a -> STM [a] -- | Write a value to a TBQueue; blocks if the queue is full. writeTBQueue :: 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. unGetTBQueue :: TBQueue a -> a -> STM () -- | Return the length of a TBQueue. lengthTBQueue :: TBQueue a -> STM Natural -- | Returns True if the supplied TBQueue is empty. isEmptyTBQueue :: TBQueue a -> STM Bool -- | Returns True if the supplied TBQueue is full. isFullTBQueue :: TBQueue a -> STM Bool -- | Lifted functions from Data.ByteString.Lazy.Char8 that are -- related to standard streams. Like the original module, you probably -- want to import this module qualified to avoid name clashes with the -- functions provided by Prelude, e.g.: -- --
-- import Data.ByteString.Lazy.Char8 (ByteString) -- import qualified Data.ByteString.Lazy.Char8 as LBS8 -- import Effectful.Console.ByteString.Lazy (Console) -- import qualified Effectful.Console.ByteString.Lazy as Console --module Effectful.Console.ByteString.Lazy -- | An effect for reading from/writing to stdin, stdout or -- stderr. data Console :: Effect -- | Run the Console effect. runConsole :: IOE :> es => Eff (Console : es) a -> Eff es a -- | Lifted getContents. getContents :: Console :> es => Eff es ByteString -- | Lifted putStr. putStr :: Console :> es => ByteString -> Eff es () -- | Lifted putStrLn. putStrLn :: Console :> es => ByteString -> Eff es () -- | Lifted interact. interact :: Console :> es => (ByteString -> ByteString) -> Eff es () -- | Lifted functions from Data.ByteString.Char8 that are related to -- standard streams. Like the original module, you probably want to -- import this module qualified to avoid name clashes with the functions -- provided by Prelude, e.g.: -- --
-- import Data.ByteString (ByteString) -- import qualified Data.ByteString.Char8 as BS8 -- import Effectful.Console.ByteString (Console) -- import qualified Effectful.Console.ByteString as Console --module Effectful.Console.ByteString -- | An effect for reading from/writing to stdin, stdout or -- stderr. data Console :: Effect -- | Run the Console effect. runConsole :: IOE :> es => Eff (Console : es) a -> Eff es a -- | Lifted getLine. getLine :: Console :> es => Eff es ByteString -- | Lifted getContents. getContents :: Console :> es => Eff es ByteString -- | Lifted putStr. putStr :: Console :> es => ByteString -> Eff es () -- | Lifted putStrLn. putStrLn :: Console :> es => ByteString -> Eff es () -- | Lifted interact. interact :: Console :> es => (ByteString -> ByteString) -> Eff es () module Effectful.Environment -- | An effect for querying and modifying the system environment. data Environment :: Effect -- | Run the Environment effect. runEnvironment :: IOE :> es => Eff (Environment : es) a -> Eff es a -- | Lifted getArgs. getArgs :: Environment :> es => Eff es [String] -- | Lifted getProgName. getProgName :: Environment :> es => Eff es String -- | Lifted getExecutablePath. getExecutablePath :: Environment :> es => Eff es FilePath -- | Lifted getEnv. getEnv :: Environment :> es => String -> Eff es String -- | Lifted getEnvironment. getEnvironment :: Environment :> es => Eff es [(String, String)] -- | Lifted lookupEnv. lookupEnv :: Environment :> es => String -> Eff es (Maybe String) -- | Lifted setEnv. setEnv :: Environment :> es => String -> String -> Eff es () -- | Lifted unsetEnv. unsetEnv :: Environment :> es => String -> Eff es () -- | Lifted withArgs. withArgs :: Environment :> es => [String] -> Eff es a -> Eff es a -- | Lifted withProgName. withProgName :: Environment :> es => String -> Eff es a -> Eff es a module Effectful.FileSystem -- | An effect for interacting with the filesystem. data FileSystem :: Effect -- | Run the FileSystem effect. runFileSystem :: IOE :> es => Eff (FileSystem : es) a -> Eff es a -- | Lifted createDirectory. createDirectory :: FileSystem :> es => FilePath -> Eff es () -- | Lifted createDirectoryIfMissing. createDirectoryIfMissing :: FileSystem :> es => Bool -> FilePath -> Eff es () -- | Lifted removeDirectory. removeDirectory :: FileSystem :> es => FilePath -> Eff es () -- | Lifted removeDirectoryRecursive. removeDirectoryRecursive :: FileSystem :> es => FilePath -> Eff es () -- | Lifted removePathForcibly. removePathForcibly :: FileSystem :> es => FilePath -> Eff es () -- | Lifted renameDirectory. renameDirectory :: FileSystem :> es => FilePath -> FilePath -> Eff es () -- | Lifted listDirectory. listDirectory :: FileSystem :> es => FilePath -> Eff es [FilePath] -- | Lifted getDirectoryContents. getDirectoryContents :: FileSystem :> es => FilePath -> Eff es [FilePath] -- | Lifted getCurrentDirectory. getCurrentDirectory :: FileSystem :> es => Eff es FilePath -- | Lifted setCurrentDirectory. setCurrentDirectory :: FileSystem :> es => FilePath -> Eff es () -- | Lifted withCurrentDirectory. withCurrentDirectory :: FileSystem :> es => FilePath -> Eff es a -> Eff es a -- | Lifted getHomeDirectory. getHomeDirectory :: FileSystem :> es => Eff es FilePath -- | Lifted getXdgDirectory. getXdgDirectory :: FileSystem :> es => XdgDirectory -> FilePath -> Eff es FilePath -- | Lifted getXdgDirectoryList. getXdgDirectoryList :: FileSystem :> es => XdgDirectoryList -> Eff es [FilePath] -- | Lifted getAppUserDataDirectory. getAppUserDataDirectory :: FileSystem :> es => FilePath -> Eff es FilePath -- | Lifted getUserDocumentsDirectory. getUserDocumentsDirectory :: FileSystem :> es => Eff es FilePath -- | Lifted getTemporaryDirectory. getTemporaryDirectory :: FileSystem :> es => Eff es FilePath -- | Lifted removeFile. removeFile :: FileSystem :> es => FilePath -> Eff es () -- | Lifted renameFile. renameFile :: FileSystem :> es => FilePath -> FilePath -> Eff es () -- | Lifted renamePath. renamePath :: FileSystem :> es => FilePath -> FilePath -> Eff es () -- | Lifted copyFile. copyFile :: FileSystem :> es => FilePath -> FilePath -> Eff es () -- | Lifted copyFileWithMetadata. copyFileWithMetadata :: FileSystem :> es => FilePath -> FilePath -> Eff es () -- | Lifted getFileSize. getFileSize :: FileSystem :> es => FilePath -> Eff es Integer -- | Lifted canonicalizePath. canonicalizePath :: FileSystem :> es => FilePath -> Eff es FilePath -- | Lifted makeAbsolute. makeAbsolute :: FileSystem :> es => FilePath -> Eff es FilePath -- | Lifted makeRelativeToCurrentDirectory. makeRelativeToCurrentDirectory :: FileSystem :> es => FilePath -> Eff es FilePath -- | Lifted doesPathExist. doesPathExist :: FileSystem :> es => FilePath -> Eff es Bool -- | Lifted doesFileExist. doesFileExist :: FileSystem :> es => FilePath -> Eff es Bool -- | Lifted doesDirectoryExist. doesDirectoryExist :: FileSystem :> es => FilePath -> Eff es Bool -- | Lifted findExecutable. findExecutable :: FileSystem :> es => String -> Eff es (Maybe FilePath) -- | Lifted findExecutables. findExecutables :: FileSystem :> es => String -> Eff es [FilePath] -- | Lifted findExecutablesInDirectories. findExecutablesInDirectories :: FileSystem :> es => [FilePath] -> String -> Eff es [FilePath] -- | Lifted findFile. findFile :: FileSystem :> es => [FilePath] -> String -> Eff es (Maybe FilePath) -- | Lifted findFiles. findFiles :: FileSystem :> es => [FilePath] -> String -> Eff es [FilePath] -- | Lifted findFileWith. findFileWith :: FileSystem :> es => (FilePath -> Eff es Bool) -> [FilePath] -> String -> Eff es (Maybe FilePath) -- | Lifted findFilesWith. findFilesWith :: FileSystem :> es => (FilePath -> Eff es Bool) -> [FilePath] -> String -> Eff es [FilePath] -- | Lifted createFileLink. createFileLink :: FileSystem :> es => FilePath -> FilePath -> Eff es () -- | Lifted createDirectoryLink. createDirectoryLink :: FileSystem :> es => FilePath -> FilePath -> Eff es () -- | Lifted removeDirectoryLink. removeDirectoryLink :: FileSystem :> es => FilePath -> Eff es () -- | Lifted pathIsSymbolicLink. pathIsSymbolicLink :: FileSystem :> es => FilePath -> Eff es Bool -- | Lifted getSymbolicLinkTarget. getSymbolicLinkTarget :: FileSystem :> es => FilePath -> Eff es FilePath -- | Lifted getPermissions. getPermissions :: FileSystem :> es => FilePath -> Eff es Permissions -- | Lifted setPermissions. setPermissions :: FileSystem :> es => FilePath -> Permissions -> Eff es () -- | Lifted copyPermissions. copyPermissions :: FileSystem :> es => FilePath -> FilePath -> Eff es () -- | Lifted getAccessTime. getAccessTime :: FileSystem :> es => FilePath -> Eff es UTCTime -- | Lifted getModificationTime. getModificationTime :: FileSystem :> es => FilePath -> Eff es UTCTime -- | Lifted setAccessTime. setAccessTime :: FileSystem :> es => FilePath -> UTCTime -> Eff es () -- | Lifted setModificationTime. setModificationTime :: FileSystem :> es => FilePath -> UTCTime -> Eff es () -- | Special directories for storing user-specific application data, -- configuration, and cache files, as specified by the XDG Base -- Directory Specification. -- -- Note: On Windows, XdgData and XdgConfig usually map to -- the same directory. data () => XdgDirectory -- | For data files (e.g. images). It uses the XDG_DATA_HOME -- environment variable. On non-Windows systems, the default is -- ~/.local/share. On Windows, the default is %APPDATA% -- (e.g. C:/Users/<user>/AppData/Roaming). Can be -- considered as the user-specific equivalent of /usr/share. XdgData :: XdgDirectory -- | For configuration files. It uses the XDG_CONFIG_HOME -- environment variable. On non-Windows systems, the default is -- ~/.config. On Windows, the default is %APPDATA% -- (e.g. C:/Users/<user>/AppData/Roaming). Can be -- considered as the user-specific equivalent of /etc. XdgConfig :: XdgDirectory -- | For non-essential files (e.g. cache). It uses the -- XDG_CACHE_HOME environment variable. On non-Windows systems, -- the default is ~/.cache. On Windows, the default is -- %LOCALAPPDATA% (e.g. -- C:/Users/<user>/AppData/Local). Can be -- considered as the user-specific equivalent of /var/cache. XdgCache :: XdgDirectory -- | For data that should persist between (application) restarts, but that -- is not important or portable enough to the user that it should be -- stored in XdgData. It uses the XDG_STATE_HOME -- environment variable. On non-Windows sytems, the default is -- ~/.local/state. On Windows, the default is -- %LOCALAPPDATA% (e.g. -- C:/Users/<user>/AppData/Local). XdgState :: XdgDirectory -- | Search paths for various application data, as specified by the XDG -- Base Directory Specification. -- -- The list of paths is split using searchPathSeparator, which on -- Windows is a semicolon. -- -- Note: On Windows, XdgDataDirs and XdgConfigDirs usually -- yield the same result. data () => XdgDirectoryList -- | For data files (e.g. images). It uses the XDG_DATA_DIRS -- environment variable. On non-Windows systems, the default is -- /usr/local/share/ and /usr/share/. On Windows, the -- default is %PROGRAMDATA% or %ALLUSERSPROFILE% (e.g. -- C:/ProgramData). XdgDataDirs :: XdgDirectoryList -- | For configuration files. It uses the XDG_CONFIG_DIRS -- environment variable. On non-Windows systems, the default is -- /etc/xdg. On Windows, the default is %PROGRAMDATA% -- or %ALLUSERSPROFILE% (e.g. C:/ProgramData). XdgConfigDirs :: XdgDirectoryList -- | Filename extension for executable files (including the dot if any) -- (usually "" on POSIX systems and ".exe" on Windows -- or OS/2). exeExtension :: String data () => Permissions emptyPermissions :: Permissions readable :: Permissions -> Bool writable :: Permissions -> Bool executable :: Permissions -> Bool searchable :: Permissions -> Bool setOwnerReadable :: Bool -> Permissions -> Permissions setOwnerWritable :: Bool -> Permissions -> Permissions setOwnerExecutable :: Bool -> Permissions -> Permissions setOwnerSearchable :: Bool -> Permissions -> Permissions -- | Lifted System.IO. module Effectful.FileSystem.IO -- | An effect for interacting with the filesystem. data FileSystem :: Effect -- | Run the FileSystem effect. runFileSystem :: IOE :> es => Eff (FileSystem : es) a -> Eff es a -- | See openFile data () => IOMode ReadMode :: IOMode WriteMode :: IOMode AppendMode :: IOMode ReadWriteMode :: IOMode -- | 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: -- --
-- import Data.ByteString (ByteString) -- import qualified Data.ByteString as BS -- import qualified Effectful.FileSystem.IO.ByteString as EBS --module Effectful.FileSystem.IO.ByteString -- | Lifted fromFilePath. fromFilePath :: FileSystem :> es => FilePath -> Eff es ByteString -- | Lifted toFilePath. toFilePath :: FileSystem :> es => ByteString -> Eff es FilePath -- | Lifted readFile. readFile :: FileSystem :> es => FilePath -> Eff es ByteString -- | Lifted writeFile. writeFile :: FileSystem :> es => FilePath -> ByteString -> Eff es () -- | Lifted appendFile. appendFile :: FileSystem :> es => FilePath -> ByteString -> Eff es () -- | Lifted hGetLine. hGetLine :: FileSystem :> es => Handle -> Eff es ByteString -- | Lifted hGetContents. hGetContents :: FileSystem :> es => Handle -> Eff es ByteString -- | Lifted hGet. hGet :: FileSystem :> es => Handle -> Int -> Eff es ByteString -- | Lifted hGetSome. hGetSome :: FileSystem :> es => Handle -> Int -> Eff es ByteString -- | Lifted hGetNonBlocking. hGetNonBlocking :: FileSystem :> es => Handle -> Int -> Eff es ByteString -- | Lifted hPut. hPut :: FileSystem :> es => Handle -> ByteString -> Eff es () -- | Lifted hPutNonBlocking. hPutNonBlocking :: FileSystem :> es => Handle -> ByteString -> Eff es ByteString -- | Lifted hPutStr. hPutStr :: FileSystem :> es => Handle -> ByteString -> Eff es () -- | Lifted hPutStrLn. hPutStrLn :: FileSystem :> es => Handle -> ByteString -> Eff es () -- | Lifted Data.ByteString.Builder. Like the original module, you -- probably want to import this module qualified to avoid name clashes -- with the functions provided by Prelude, e.g.: -- --
-- import Data.ByteString.Builder (Builder) -- import qualified Data.ByteString.Builder as BSB -- import qualified Effectful.FileSystem.IO.ByteString.Builder as EBSB --module Effectful.FileSystem.IO.ByteString.Builder -- | Lifted hPutBuilder. hPutBuilder :: FileSystem :> es => Handle -> Builder -> Eff es () -- | Lifted writeFile. writeFile :: FileSystem :> es => FilePath -> Builder -> Eff es () -- | Lifted Data.ByteString.Lazy.Char8. Like the original module, -- you probably want to import this module qualified to avoid name -- clashes with the functions provided by Prelude, e.g.: -- --
-- import Data.ByteString.Lazy (ByteString) -- import qualified Data.ByteString.Lazy.Char8 as LBS8 -- import qualified Effectful.FileSystem.IO.ByteString.Lazy as ELBS --module Effectful.FileSystem.IO.ByteString.Lazy -- | Lifted readFile. readFile :: FileSystem :> es => FilePath -> Eff es ByteString -- | Lifted writeFile. writeFile :: FileSystem :> es => FilePath -> ByteString -> Eff es () -- | Lifted appendFile. appendFile :: FileSystem :> es => FilePath -> ByteString -> Eff es () -- | Lifted hGetContents. hGetContents :: FileSystem :> es => Handle -> Eff es ByteString -- | Lifted hGet. hGet :: FileSystem :> es => Handle -> Int -> Eff es ByteString -- | Lifted hGetNonBlocking. hGetNonBlocking :: FileSystem :> es => Handle -> Int -> Eff es ByteString -- | Lifted hPut. hPut :: FileSystem :> es => Handle -> ByteString -> Eff es () -- | Lifted hPutNonBlocking. hPutNonBlocking :: FileSystem :> es => Handle -> ByteString -> Eff es ByteString -- | Lifted hPutStr. hPutStr :: FileSystem :> es => Handle -> ByteString -> Eff es () -- | Lifted hPutStrLn. hPutStrLn :: FileSystem :> es => Handle -> ByteString -> Eff es () -- | Lifted UnliftIO.IO.File. module Effectful.FileSystem.IO.File -- | Lifted writeBinaryFile. writeBinaryFile :: FileSystem :> es => FilePath -> ByteString -> Eff es () -- | Lifted writeBinaryFileAtomic. writeBinaryFileAtomic :: FileSystem :> es => FilePath -> ByteString -> Eff es () -- | Lifted writeBinaryFileDurable. writeBinaryFileDurable :: FileSystem :> es => FilePath -> ByteString -> Eff es () -- | Lifted writeBinaryFileDurableAtomic. writeBinaryFileDurableAtomic :: FileSystem :> es => FilePath -> ByteString -> Eff es () -- | Lifted withBinaryFile. withBinaryFile :: FileSystem :> es => FilePath -> IOMode -> (Handle -> Eff es a) -> Eff es a -- | Lifted withBinaryFileAtomic. withBinaryFileAtomic :: FileSystem :> es => FilePath -> IOMode -> (Handle -> Eff es a) -> Eff es a -- | Lifted withBinaryFileDurable. withBinaryFileDurable :: FileSystem :> es => FilePath -> IOMode -> (Handle -> Eff es a) -> Eff es a -- | Lifted withBinaryFileDurableAtomic. withBinaryFileDurableAtomic :: FileSystem :> es => FilePath -> IOMode -> (Handle -> Eff es a) -> Eff es a -- | Lifted ensureFileDurable. ensureFileDurable :: FileSystem :> es => FilePath -> Eff es () -- | Lifted System.Process. module Effectful.Process -- | An effect for running child processes using the process -- library. data Process :: Effect runProcess :: IOE :> es => Eff (Process : es) a -> Eff es a -- | Lifted createProcess. createProcess :: Process :> es => CreateProcess -> Eff es (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -- | Lifted createProcess_. createProcess_ :: Process :> es => String -> CreateProcess -> Eff es (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -- | Construct a CreateProcess record for passing to -- createProcess, representing a command to be passed to the -- shell. shell :: String -> CreateProcess -- | Construct a CreateProcess record for passing to -- createProcess, representing a raw command with arguments. -- -- See RawCommand for precise semantics of the specified -- FilePath. proc :: FilePath -> [String] -> CreateProcess data () => CreateProcess CreateProcess :: CmdSpec -> Maybe FilePath -> Maybe [(String, String)] -> StdStream -> StdStream -> StdStream -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Maybe GroupID -> Maybe UserID -> Bool -> CreateProcess -- | Executable & arguments, or shell command. If cwd is -- Nothing, relative paths are resolved with respect to the -- current working directory. If cwd is provided, it is -- implementation-dependent whether relative paths are resolved with -- respect to cwd or the current working directory, so absolute -- paths should be used to ensure portability. [cmdspec] :: CreateProcess -> CmdSpec -- | Optional path to the working directory for the new process [cwd] :: CreateProcess -> Maybe FilePath -- | Optional environment (otherwise inherit from the current process) [env] :: CreateProcess -> Maybe [(String, String)] -- | How to determine stdin [std_in] :: CreateProcess -> StdStream -- | How to determine stdout [std_out] :: CreateProcess -> StdStream -- | How to determine stderr [std_err] :: CreateProcess -> StdStream -- | Close all file descriptors except stdin, stdout and stderr in the new -- process (on Windows, only works if std_in, std_out, and std_err are -- all Inherit). This implementation will call close on every fd from 3 -- to the maximum of open files, which can be slow for high maximum of -- open files. [close_fds] :: CreateProcess -> Bool -- | Create a new process group [create_group] :: CreateProcess -> Bool -- | Delegate control-C handling. Use this for interactive console -- processes to let them handle control-C themselves (see below for -- details). -- -- On Windows this has no effect. [delegate_ctlc] :: CreateProcess -> Bool -- | Use the windows DETACHED_PROCESS flag when creating the process; does -- nothing on other platforms. [detach_console] :: CreateProcess -> Bool -- | Use the windows CREATE_NEW_CONSOLE flag when creating the process; -- does nothing on other platforms. -- -- Default: False [create_new_console] :: CreateProcess -> Bool -- | Use posix setsid to start the new process in a new session; does -- nothing on other platforms. [new_session] :: CreateProcess -> Bool -- | Use posix setgid to set child process's group id; does nothing on -- other platforms. -- -- Default: Nothing [child_group] :: CreateProcess -> Maybe GroupID -- | Use posix setuid to set child process's user id; does nothing on other -- platforms. -- -- Default: Nothing [child_user] :: CreateProcess -> Maybe UserID -- | On Windows systems this flag indicates that we should wait for the -- entire process tree to finish before unblocking. On POSIX systems this -- flag is ignored. See $exec-on-windows for details. -- -- Default: False [use_process_jobs] :: CreateProcess -> Bool data () => CmdSpec -- | A command line to execute using the shell ShellCommand :: String -> CmdSpec -- | The name of an executable with a list of arguments -- -- The FilePath argument names the executable, and is interpreted -- according to the platform's standard policy for searching for -- executables. Specifically: -- --