on master help sign in
Describe caveats of the Concurrent effect
commit4704c35d4840497bacb0260310440601f38e8587 authorAndrzej Rybczak <andrzej@rybczak.net> dateSun 19 Dec 2021, 20:19 (5 years ago) parent6c09a2f
21 files changed+231−168
effectful-core/src/Effectful.hs+3−3 effectful-core/src/Effectful/Dispatch/Dynamic.hs+12−12 effectful-core/src/Effectful/Dispatch/Static.hs+6−6 effectful-core/src/Effectful/Error.hs+4−4 effectful-core/src/Effectful/Internal/Effect.hs+3−3 effectful-core/src/Effectful/Internal/Monad.hs+17−17 effectful-core/src/Effectful/Internal/Unlift.hs+2−2 effectful-core/src/Effectful/State/Shared.hs+3−3 effectful-core/src/Effectful/Writer/Shared.hs+3−3 effectful/src/Effectful/Concurrent.hs+15−2 effectful/src/Effectful/Concurrent/Async.hs+2−2 effectful/src/Effectful/Concurrent/Chan.hs+1−2 effectful/src/Effectful/Concurrent/Effect.hs+63−4 effectful/src/Effectful/Concurrent/MVar.hs+1−2 effectful/src/Effectful/Concurrent/QSem.hs+2−3 effectful/src/Effectful/Concurrent/QSemN.hs+2−3 effectful/src/Effectful/Concurrent/STM.hs+1−2 effectful/src/Effectful/Environment.hs+1−2 effectful/src/Effectful/FileSystem.hs+88−89 effectful/src/Effectful/FileSystem/IO.hs+1−2 effectful/src/Effectful/Process.hs+1−2
effectful-core/src/Effectful.hs+3−3
@@ -8,10 +8,10 @@ module Effectful
88
99 -- * Running the 'Eff' monad
1010
11− -- ** Pure operations
11+ -- ** Pure computations
1212 , runPureEff
1313
14− -- ** Operations with side effects
14+ -- ** Computations with side effects
1515 , IOE
1616 , runEff
1717
@@ -32,7 +32,7 @@ module Effectful
3232 , interpret
3333 , reinterpret
3434
35− -- ** Handling local 'Eff' operations
35+ -- ** Handling local 'Eff' computations
3636 , LocalEnv
3737
3838 -- *** Unlifts
effectful-core/src/Effectful/Dispatch/Dynamic.hs+12−12
@@ -7,7 +7,7 @@ module Effectful.Dispatch.Dynamic
77 , interpret
88 , reinterpret
99
10− -- ** Handling local 'Eff' operations
10+ -- ** Handling local 'Eff' computations
1111 , LocalEnv
1212
1313 -- *** Unlifts
@@ -121,7 +121,7 @@ localUnliftIO (LocalEnv les) strategy k = case strategy of
121121 SeqUnlift -> liftIO $ seqUnliftIO les k
122122 ConcUnlift p l -> liftIO $ concUnliftIO les p l k
123123
124−-- | Utility for lifting 'Eff' operations of type
124+-- | Utility for lifting 'Eff' computations of type
125125--
126126-- @'Eff' es a -> 'Eff' es b@
127127--
@@ -129,7 +129,7 @@ localUnliftIO (LocalEnv les) strategy k = case strategy of
129129--
130130-- @'Eff' localEs a -> 'Eff' localEs b@
131131--
132−-- /Note:/ the operation must not run its argument in a separate thread,
132+-- /Note:/ the computation must not run its argument in a separate thread,
133133-- attempting to do so will result in a runtime error.
134134withLiftMap
135135 :: (HasCallStack, SuffixOf es handlerEs)
@@ -145,7 +145,7 @@ withLiftMap !_ k = unsafeEff $ \es -> do
145145 seqUnliftIO localEs $ \unlift -> do
146146 (`unEff` es) . mapEff . unsafeEff_ $ unlift m
147147
148−-- | Utility for lifting 'IO' operations of type
148+-- | Utility for lifting 'IO' computations of type
149149--
150150-- @'IO' a -> 'IO' b@
151151--
@@ -153,11 +153,11 @@ withLiftMap !_ k = unsafeEff $ \es -> do
153153--
154154-- @'Eff' localEs a -> 'Eff' localEs b@
155155--
156−-- /Note:/ the operation must not run its argument in a separate thread,
156+-- /Note:/ the computation must not run its argument in a separate thread,
157157-- attempting to do so will result in a runtime error.
158158--
159159-- Useful e.g. for lifting the unmasking function in
160−-- 'Control.Exception.mask'-like operations:
160+-- 'Control.Exception.mask'-like computations:
161161--
162162-- >>> :{
163163-- data Fork :: Effect where
@@ -187,10 +187,10 @@ withLiftMapIO !_ k = k $ \mapIO m -> unsafeEff $ \es -> do
187187
188188-- | Create a local lifting and unlifting function with the given strategy.
189189--
190−-- Useful for lifting complicated 'Eff' operations where the monadic action
190+-- Useful for lifting complicated 'Eff' computations where the monadic action
191191-- shows in both positive (as a result) and negative (as an argument) position.
192192--
193−-- /Note:/ depending on the operation you're lifting 'localUnlift' along with
193+-- /Note:/ depending on the computation you're lifting 'localUnlift' along with
194194-- 'withLiftMap' might be enough and is more efficient.
195195localLiftUnlift
196196 :: (HasCallStack, SuffixOf es handlerEs)
@@ -213,11 +213,11 @@ localLiftUnlift (LocalEnv les) strategy k = case strategy of
213213-- | Create a local unlifting function with the given strategy along with an
214214-- unrestricted lifting function.
215215--
216−-- Useful for lifting complicated 'IO' operations where the monadic action shows
217−-- in both positive (as a result) and negative (as an argument) position.
216+-- Useful for lifting complicated 'IO' computations where the monadic action
217+-- shows in both positive (as a result) and negative (as an argument) position.
218218--
219−-- /Note:/ depending on the operation you're lifting 'localUnliftIO' along with
220−-- 'withLiftMapIO' might be enough and is more efficient.
219+-- /Note:/ depending on the computation you're lifting 'localUnliftIO' along
220+-- with 'withLiftMapIO' might be enough and is more efficient.
221221localLiftUnliftIO
222222 :: (HasCallStack, SuffixOf es handlerEs, IOE :> es)
223223 => LocalEnv localEs handlerEs
effectful-core/src/Effectful/Dispatch/Static.hs+6−6
@@ -54,7 +54,7 @@ import Effectful.Internal.Effect
5454import Effectful.Internal.Env
5555import Effectful.Internal.Monad
5656
57−-- | Utility for lifting 'IO' operations of type
57+-- | Utility for lifting 'IO' computations of type
5858--
5959-- @'IO' a -> 'IO' b@
6060--
@@ -65,10 +65,10 @@ import Effectful.Internal.Monad
6565-- This function is __unsafe__ because:
6666--
6767-- - It can be used to introduce arbitrary 'IO' actions into pure 'Eff'
68−-- operations.
68+-- computations.
6969--
70−-- - The 'IO' operation must not run its argument in a separate thread, but it's
71−-- not checked anywhere.
70+-- - The 'IO' computation must not run its argument in a separate thread, but
71+-- it's not checked anywhere.
7272unsafeLiftMapIO :: (IO a -> IO b) -> Eff es a -> Eff es b
7373unsafeLiftMapIO f m = unsafeEff $ \es -> f (unEff m es)
7474
@@ -77,9 +77,9 @@ unsafeLiftMapIO f m = unsafeEff $ \es -> f (unEff m es)
7777-- This function is __unsafe__ because:
7878--
7979-- - It can be used to introduce arbitrary 'IO' actions into pure 'Eff'
80−-- operations.
80+-- computations.
8181--
82−-- - Unlifted 'Eff' operations must not be run in a thread distinct from the
82+-- - Unlifted 'Eff' computations must not be run in a thread distinct from the
8383-- caller of 'unsafeUnliftIO', but it's not checked anywhere.
8484unsafeUnliftIO :: ((forall r. Eff es r -> IO r) -> IO a) -> Eff es a
8585unsafeUnliftIO k = unsafeEff $ \es -> k (`unEff` es)
effectful-core/src/Effectful/Error.hs+4−4
@@ -25,12 +25,12 @@
2525-- resources such as 'Control.Monad.Catch.finally' and
2626-- 'Control.Monad.Catch.bracket' work as expected:
2727--
28−-- >>> let display = liftIO . putStrLn
28+-- >>> let msg = liftIO . putStrLn
2929-- >>> :{
3030-- runEff . fmap (either (Left . snd) Right) . runError @String $ do
31−-- E.bracket_ (display "Beginning.")
32−-- (display "Cleaning up.")
33−-- (display "Computing." >> throwError "oops" >> display "More.")
31+-- E.bracket_ (msg "Beginning.")
32+-- (msg "Cleaning up.")
33+-- (msg "Computing." >> throwError "oops" >> msg "More.")
3434-- :}
3535-- Beginning.
3636-- Computing.
effectful-core/src/Effectful/Internal/Effect.hs+3−3
@@ -29,10 +29,10 @@ newtype IdA :: Effect -> Type where
2929
3030-- | A constraint that requires that a particular effect @e@ is a member of the
3131-- type-level list @es@. This is used to parameterize an 'Effectful.Monad.Eff'
32−-- operation over an arbitrary list of effects, so long as @e@ is /somewhere/ in
33−-- the list.
32+-- computation over an arbitrary list of effects, so long as @e@ is /somewhere/
33+-- in the list.
3434--
35−-- For example, an operation that only needs access to a mutable value of type
35+-- For example, a computation that only needs access to a mutable value of type
3636-- 'Integer' would likely use the following type:
3737--
3838-- @
effectful-core/src/Effectful/Internal/Monad.hs+17−17
@@ -84,12 +84,12 @@ import Effectful.Internal.Unlift
8484
8585type role Eff nominal representational
8686
87−-- | The 'Eff' monad provides the implementation of an operation that performs
87+-- | The 'Eff' monad provides the implementation of a computation that performs
8888-- an arbitrary set of effects. In @'Eff' es a@, @es@ is a type-level list that
89−-- contains all the effects that the operation may perform. For example, an
90−-- operation that produces an 'Integer' by consuming a 'String' from the global
91−-- environment and acting upon a single mutable value of type 'Bool' would have
92−-- the following type:
89+-- contains all the effects that the computation may perform. For example, a
90+-- computation that produces an 'Integer' by consuming a 'String' from the
91+-- global environment and acting upon a single mutable value of type 'Bool'
92+-- would have the following type:
9393--
9494-- @
9595-- 'Eff' '['Effectful.Reader.Reader' 'String', 'Effectful.State.State' 'Bool'] 'Integer'
@@ -97,7 +97,7 @@ type role Eff nominal representational
9797--
9898-- Normally, a concrete list of effects is not used to parameterize 'Eff'.
9999-- Instead, the '(:>)' type class is used to express constraints on the list of
100−-- effects without coupling an operation to a concrete list of effects. For
100+-- effects without coupling a computation to a concrete list of effects. For
101101-- example, the above example would more commonly be expressed with the
102102-- following type:
103103--
@@ -105,15 +105,15 @@ type role Eff nominal representational
105105-- ('Effectful.Reader.Reader' 'String' ':>' es, 'Effectful.State.State' 'Bool' ':>' es) => 'Eff' es 'Integer'
106106-- @
107107--
108−-- This abstraction allows the operation to be used in functions that may
108+-- This abstraction allows the computation to be used in functions that may
109109-- perform other effects, and it also allows the effects to be handled in any
110110-- order.
111111newtype Eff (es :: [Effect]) a = Eff (Env es -> IO a)
112112 deriving (Monoid, Semigroup)
113113
114−-- | Run a pure 'Eff' operation.
114+-- | Run a pure 'Eff' computation.
115115--
116−-- For running operations with side effects see 'runEff'.
116+-- For running computations with side effects see 'runEff'.
117117runPureEff :: Eff '[] a -> a
118118runPureEff (Eff m) =
119119 -- unsafePerformIO is safe here since IOE was not on the stack, so no IO with
@@ -134,14 +134,14 @@ unEff (Eff m) = m
134134-- | Access the underlying 'IO' monad along with the environment.
135135--
136136-- This function is __unsafe__ because it can be used to introduce arbitrary
137−-- 'IO' actions into pure 'Eff' operations.
137+-- 'IO' actions into pure 'Eff' computations.
138138unsafeEff :: (Env es -> IO a) -> Eff es a
139139unsafeEff m = Eff (oneShot m)
140140
141141-- | Access the underlying 'IO' monad.
142142--
143143-- This function is __unsafe__ because it can be used to introduce arbitrary
144−-- 'IO' actions into pure 'Eff' operations.
144+-- 'IO' actions into pure 'Eff' computations.
145145unsafeEff_ :: IO a -> Eff es a
146146unsafeEff_ m = unsafeEff $ \_ -> m
147147
@@ -264,13 +264,13 @@ instance Fail :> es => MonadFail (Eff es) where
264264----------------------------------------
265265-- IO
266266
267−-- | Run arbitrary 'IO' operations via 'MonadIO' or 'MonadUnliftIO'.
267+-- | Run arbitrary 'IO' computations via 'MonadIO' or 'MonadUnliftIO'.
268268newtype IOE :: Effect where
269269 IOE :: UnliftStrategy -> IOE m r
270270
271−-- | Run an 'Eff' operation with side effects.
271+-- | Run an 'Eff' computation with side effects.
272272--
273−-- For running pure operations see 'runPureEff'.
273+-- For running pure computations see 'runPureEff'.
274274runEff :: Eff '[IOE] a -> IO a
275275runEff m = unEff (evalEffect (IdA (IOE SeqUnlift)) m) =<< emptyEnv
276276
@@ -300,7 +300,7 @@ instance IOE :> es => MonadBaseControl IO (Eff es) where
300300data Prim :: Effect where
301301 Prim :: Prim m r
302302
303−-- | Run an 'Eff' operation with primitive state-transformer actions.
303+-- | Run an 'Eff' computation with primitive state-transformer actions.
304304runPrim :: IOE :> es => Eff (Prim : es) a -> Eff es a
305305runPrim = evalEffect (IdA Prim)
306306
@@ -325,8 +325,8 @@ newtype LocalEnv (localEs :: [Effect]) (handlerEs :: [Effect]) = LocalEnv (Env l
325325type EffectHandler e es
326326 = forall a localEs. HasCallStack
327327 => LocalEnv localEs es
328− -- ^ Capture of the local environment for handling local 'Eff' operations when
329− -- @e@ is a higher order effect.
328+ -- ^ Capture of the local environment for handling local 'Eff' computations
329+ -- when @e@ is a higher order effect.
330330 -> e (Eff localEs) a
331331 -- ^ The effect performed in the local environment.
332332 -> Eff es a
effectful-core/src/Effectful/Internal/Unlift.hs+2−2
@@ -35,7 +35,7 @@ import Effectful.Internal.Utils
3535----------------------------------------
3636-- Unlift strategies
3737
38−-- | The strategy to use when unlifting 'Eff' operations via 'withRunInIO',
38+-- | The strategy to use when unlifting 'Eff' computations via 'withRunInIO',
3939-- 'Effectful.Monad.withEffToIO' or the 'Effectful.Dispatch.Dynamic.localUnlift'
4040-- family.
4141data UnliftStrategy
@@ -105,7 +105,7 @@ seqUnlift k es unEff = do
105105 if tid `eqThreadId` tid0
106106 then unEff m es
107107 else error
108− $ "If you want to use the unlifting function to run Eff operations "
108+ $ "If you want to use the unlifting function to run Eff computations "
109109 ++ "in multiple threads, have a look at UnliftStrategy (ConcUnlift)."
110110
111111-- | Concurrent unlift for various strategies and limits.
effectful-core/src/Effectful/State/Shared.hs+3−3
@@ -1,7 +1,7 @@
11-- | Support for access to a mutable value of a particular type, which is:
22--
3−-- - shareable between multiple threads (if you want each thead to manage their
4−-- own version of the value, see "Effectful.State.Local").
3+-- - shared between multiple threads (if you want each thead to manage its own
4+-- version of the value, see "Effectful.State.Local").
55--
66-- - slower than "Effectful.State.Local".
77--
@@ -24,7 +24,7 @@ import Control.Concurrent.MVar
2424import Effectful.Dispatch.Static
2525import Effectful.Monad
2626
27−-- | Provide access to a strict (WHNF), shareable, mutable value of type @s@.
27+-- | Provide access to a strict (WHNF), shared, mutable value of type @s@.
2828newtype State s :: Effect where
2929 State :: MVar s -> State s m r
3030
effectful-core/src/Effectful/Writer/Shared.hs+3−3
@@ -1,7 +1,7 @@
11-- | Support for access to a write only value of a particular type, which is:
22--
3−-- - shareable between multiple threads (if you want each thead to manage their
4−-- own version of the value, see "Effectful.Writer.Local").
3+-- - shared between multiple threads (if you want each thead to manage its own
4+-- version of the value, see "Effectful.Writer.Local").
55--
66-- - slower than "Effectful.Writer.Local".
77--
@@ -30,7 +30,7 @@ import Control.Exception
3030import Effectful.Dispatch.Static
3131import Effectful.Monad
3232
33−-- | Provide access to a strict (WHNF), shareable, write only value of type @w@.
33+-- | Provide access to a strict (WHNF), shared, write only value of type @w@.
3434newtype Writer w :: Effect where
3535 Writer :: MVar w -> Writer w m r
3636
effectful/src/Effectful/Concurrent.hs+15−2
@@ -1,6 +1,19 @@
1+-- | Lifted version of "Control.Concurrent".
2+--
3+-- For functions that spawn threads, the order of preference for their usage is
4+-- recommended as follows:
5+--
6+-- 1) High level functions from "Effectful.Concurrent.Async" such as
7+-- 'Effectful.Concurrent.Async.withAsync',
8+-- 'Effectful.Concurrent.Async.concurrently' or
9+-- 'Effectful.Concurrent.Async.mapConcurrently'.
10+--
11+-- 2) Low level functions from "Effectful.Concurrent.Async" such as
12+-- 'Effectful.Concurrent.Async.async'.
13+--
14+-- 3) Low level functions from "Effectful.Concurrent" such as 'forkIO'.
115module Effectful.Concurrent
2− ( -- * The effect
3− Concurrent
16+ ( Concurrent
417 , runConcurrent
518
619 -- * Basic concurrency operations
effectful/src/Effectful/Concurrent/Async.hs+2−2
@@ -1,7 +1,7 @@
11{-# LANGUAGE UndecidableInstances #-}
2+-- | Lifted version of "Control.Concurrent.Async".
23module Effectful.Concurrent.Async
3− ( -- * The effect
4− Concurrent
4+ ( Concurrent
55 , runConcurrent
66
77 -- * Asynchronous actions
effectful/src/Effectful/Concurrent/Chan.hs+1−2
@@ -1,7 +1,6 @@
11-- | Lifted version of "Control.Concurrent.Chan".
22module Effectful.Concurrent.Chan
3− ( -- * The effect
4− Concurrent
3+ ( Concurrent
54 , runConcurrent
65
76 -- * Chan
effectful/src/Effectful/Concurrent/Effect.hs+63−4
@@ -6,15 +6,74 @@ module Effectful.Concurrent.Effect
66import Effectful.Dispatch.Static
77import Effectful.Monad
88
9−-- | Run 'Eff' operations asynchronously via the @async@ library.
9+-- | Provide the ability to run 'Eff' computations concurrently in multiple
10+-- threads and communicate between them.
1011--
11−-- /Note:/ thread local state changes in 'Eff' operations run asynchronously
12−-- will not affect the parent thread.
12+-- /Warning:/ unless you stick to high level functions from the
13+-- 'Effectful.Concurrent.Async.withAsync' family, the 'Concurrent' effect makes
14+-- it possible to escape the scope of any scoped effect operation. Consider the
15+-- following:
16+--
17+-- >>> import qualified Effectful.Reader as R
18+-- >>> let printAsk msg = liftIO . putStrLn . (msg ++) . (": " ++) =<< R.ask
19+-- >>> :{
20+-- runEff . R.runReader "GLOBAL" . runConcurrent $ do
21+-- a <- R.local (const "LOCAL") $ do
22+-- a <- async $ do
23+-- printAsk "child (first)"
24+-- threadDelay 20000
25+-- printAsk "child (second)"
26+-- threadDelay 10000
27+-- printAsk "parent (inside)"
28+-- pure a
29+-- printAsk "parent (outside)"
30+-- wait a
31+-- :}
32+-- child (first): LOCAL
33+-- parent (inside): LOCAL
34+-- parent (outside): GLOBAL
35+-- child (second): LOCAL
36+--
37+-- Note that the asynchronous computation doesn't respect the scope of
38+-- 'Effectful.Reader.local', i.e. the child thread still behaves like it's
39+-- inside the 'Effectful.Reader.local' block, even though the parent thread
40+-- already got out of it.
41+--
42+-- This is because the value provided by the 'Effectful.Reader.Reader' effect is
43+-- thread local, i.e. each thread manages its own version of it. For the
44+-- 'Effectful.Reader.Reader' it is the only reasonable behavior, it wouldn't be
45+-- very useful if its "read only" value was affected by calls to
46+-- 'Effectful.Reader.local' from its parent or child threads.
47+--
48+-- However, the cut isn't so clear if it comes to effects that provide access to
49+-- a mutable state. That's why the @State@ and the @Writer@ effects come in two
50+-- flavors, thread local and shared:
51+--
52+-- >>> import qualified Effectful.State.Local as SL
53+-- >>> :{
54+-- runEff . SL.execState "Hi" . runConcurrent $ do
55+-- replicateConcurrently_ 3 $ SL.modify (++ "!")
56+-- :}
57+-- "Hi"
58+--
59+-- >>> import qualified Effectful.State.Shared as SS
60+-- >>> :{
61+-- runEff . SS.execState "Hi" . runConcurrent $ do
62+-- replicateConcurrently_ 3 $ SS.modify (++ "!")
63+-- :}
64+-- "Hi!!!"
65+--
66+-- In the first example state modification made concurrently are not reflected
67+-- in the parent thread because the value is thread local, but in the second
68+-- example they are, because the value is shared.
1369--
14−-- /TODO:/ write about 'Concurrent' not respecting scoped operations.
1570data Concurrent :: Effect where
1671 Concurrent :: Concurrent m r
1772
1873-- | Run the 'Concurrent' effect.
1974runConcurrent :: IOE :> es => Eff (Concurrent : es) a -> Eff es a
2075runConcurrent = evalEffect (IdA Concurrent)
76+
77+-- $setup
78+-- >>> import Effectful.Concurrent
79+-- >>> import Effectful.Concurrent.Async
effectful/src/Effectful/Concurrent/MVar.hs+1−2
@@ -1,7 +1,6 @@
11-- | Lifted version of "Control.Concurrent.MVar".
22module Effectful.Concurrent.MVar
3− ( -- * The effect
4− Concurrent
3+ ( Concurrent
54 , runConcurrent
65
76 -- * MVar
effectful/src/Effectful/Concurrent/QSem.hs+2−3
@@ -1,7 +1,6 @@
1−-- | Lifted "Control.Concurrent.QSem".
1+-- | Lifted version of "Control.Concurrent.QSem".
22module Effectful.Concurrent.QSem
3− ( -- * The effect
4− Concurrent
3+ ( Concurrent
54 , runConcurrent
65
76 -- * QSem
effectful/src/Effectful/Concurrent/QSemN.hs+2−3
@@ -1,7 +1,6 @@
1−-- | Lifted "Control.Concurrent.QSemN".
1+-- | Lifted version of "Control.Concurrent.QSemN".
22module Effectful.Concurrent.QSemN
3− ( -- * The effect
4− Concurrent
3+ ( Concurrent
54 , runConcurrent
65
76 -- * QSemN
effectful/src/Effectful/Concurrent/STM.hs+1−2
@@ -1,7 +1,6 @@
11-- | Lifted version of "Control.Concurrent.STM".
22module Effectful.Concurrent.STM
3− ( -- * The effect
4− Concurrent
3+ ( Concurrent
54 , runConcurrent
65
76 -- * Core
effectful/src/Effectful/Environment.hs+1−2
@@ -1,6 +1,5 @@
11module Effectful.Environment
2− ( -- * The effect
3− Environment
2+ ( Environment
43 , runEnvironment
54
65 -- * Querying the environment
effectful/src/Effectful/FileSystem.hs+88−89
@@ -1,93 +1,92 @@
11module Effectful.FileSystem
2− ( -- * The effect
3− FileSystem
4− , runFileSystem
5−
6− -- * Actions on directories
7− , createDirectory
8− , createDirectoryIfMissing
9− , removeDirectory
10− , removeDirectoryRecursive
11− , removePathForcibly
12− , renameDirectory
13− , listDirectory
14− , getDirectoryContents
15−
16− -- ** Current working directory
17− , getCurrentDirectory
18− , setCurrentDirectory
19− , withCurrentDirectory
20−
21− -- * Pre-defined directories
22− , getHomeDirectory
23− , getXdgDirectory
24− , getXdgDirectoryList
25− , getAppUserDataDirectory
26− , getUserDocumentsDirectory
27− , getTemporaryDirectory
28−
29− -- * Actions on files
30− , removeFile
31− , renameFile
32− , renamePath
33− , copyFile
34− , copyFileWithMetadata
35− , getFileSize
36− , canonicalizePath
37− , makeAbsolute
38− , makeRelativeToCurrentDirectory
39−
40− -- * Existence tests
41− , doesPathExist
42− , doesFileExist
43− , doesDirectoryExist
44− , findExecutable
45− , findExecutables
46− , findExecutablesInDirectories
47− , findFile
48− , findFiles
49− , findFileWith
50− , findFilesWith
51−
52− -- * Symbolic links
53− , createFileLink
54− , createDirectoryLink
55− , removeDirectoryLink
56− , pathIsSymbolicLink
57− , getSymbolicLinkTarget
58−
59− -- * Permissions
60− , getPermissions
61− , setPermissions
62− , copyPermissions
63−
64− -- * Timestamps
65− , getAccessTime
66− , getModificationTime
67− , setAccessTime
68− , setModificationTime
69−
70− -- * Re-exports
71−
72− -- ** Pre-defined directories
73− , D.XdgDirectory(..)
74− , D.XdgDirectoryList(..)
75−
76− -- ** Existence tests
77− , D.exeExtension
78−
79− -- ** Permissions
80− , D.Permissions
81− , D.emptyPermissions
82− , D.readable
83− , D.writable
84− , D.executable
85− , D.searchable
86− , D.setOwnerReadable
87− , D.setOwnerWritable
88− , D.setOwnerExecutable
89− , D.setOwnerSearchable
90− ) where
2+ ( FileSystem
3+ , runFileSystem
4+
5+ -- * Actions on directories
6+ , createDirectory
7+ , createDirectoryIfMissing
8+ , removeDirectory
9+ , removeDirectoryRecursive
10+ , removePathForcibly
11+ , renameDirectory
12+ , listDirectory
13+ , getDirectoryContents
14+
15+ -- ** Current working directory
16+ , getCurrentDirectory
17+ , setCurrentDirectory
18+ , withCurrentDirectory
19+
20+ -- * Pre-defined directories
21+ , getHomeDirectory
22+ , getXdgDirectory
23+ , getXdgDirectoryList
24+ , getAppUserDataDirectory
25+ , getUserDocumentsDirectory
26+ , getTemporaryDirectory
27+
28+ -- * Actions on files
29+ , removeFile
30+ , renameFile
31+ , renamePath
32+ , copyFile
33+ , copyFileWithMetadata
34+ , getFileSize
35+ , canonicalizePath
36+ , makeAbsolute
37+ , makeRelativeToCurrentDirectory
38+
39+ -- * Existence tests
40+ , doesPathExist
41+ , doesFileExist
42+ , doesDirectoryExist
43+ , findExecutable
44+ , findExecutables
45+ , findExecutablesInDirectories
46+ , findFile
47+ , findFiles
48+ , findFileWith
49+ , findFilesWith
50+
51+ -- * Symbolic links
52+ , createFileLink
53+ , createDirectoryLink
54+ , removeDirectoryLink
55+ , pathIsSymbolicLink
56+ , getSymbolicLinkTarget
57+
58+ -- * Permissions
59+ , getPermissions
60+ , setPermissions
61+ , copyPermissions
62+
63+ -- * Timestamps
64+ , getAccessTime
65+ , getModificationTime
66+ , setAccessTime
67+ , setModificationTime
68+
69+ -- * Re-exports
70+
71+ -- ** Pre-defined directories
72+ , D.XdgDirectory(..)
73+ , D.XdgDirectoryList(..)
74+
75+ -- ** Existence tests
76+ , D.exeExtension
77+
78+ -- ** Permissions
79+ , D.Permissions
80+ , D.emptyPermissions
81+ , D.readable
82+ , D.writable
83+ , D.executable
84+ , D.searchable
85+ , D.setOwnerReadable
86+ , D.setOwnerWritable
87+ , D.setOwnerExecutable
88+ , D.setOwnerSearchable
89+ ) where
9190
9291import Data.Time (UTCTime)
9392import qualified System.Directory as D
effectful/src/Effectful/FileSystem/IO.hs+1−2
@@ -1,7 +1,6 @@
11-- | Lifted version of "System.IO".
22module Effectful.FileSystem.IO
3− ( -- * The effect
4− FileSystem
3+ ( FileSystem
54 , runFileSystem
65
76 -- * IO
effectful/src/Effectful/Process.hs+1−2
@@ -1,8 +1,7 @@
11{-# LANGUAGE CPP #-}
22-- | Lifted version of "System.Process".
33module Effectful.Process
4− ( -- * The effect
5− Process
4+ ( Process
65 , runProcess
76
87 -- * Running sub-processes