on master help sign in
Add top level module and basic documentation
commit9f1c163e546a2023cafd1efdc6a4b46d0bf3b871 authorAndrzej Rybczak <andrzej@rybczak.net> dateThu 1 Jul 2021, 20:22 (5 years ago) parent568ccb2
14 files changed+88−21
bench/Countdown.hs+1−1 bench/FileSizes.hs+1−2 effectful.cabal+2−1 examples/FileSystem.hs+1−2 src/Effectful.hs+35 src/Effectful/Internal/Effect.hs+12 src/Effectful/Internal/Monad.hs+27−3 src/Effectful/Interpreter.hs+3 src/Effectful/State/Dynamic.hs+1−3 src/Effectful/Writer/Dynamic.hs+1−3 tests/AsyncTests.hs+1−1 tests/ErrorTests.hs+1−2 tests/StateTests.hs+1−2 tests/Utils.hs+1−1
bench/Countdown.hs+1−1
@@ -11,7 +11,7 @@ import qualified Control.Effect as L
1111#endif
1212
1313-- effectful
14−import qualified Effectful.Monad as E
14+import qualified Effectful as E
1515import qualified Effectful.Reader as E
1616import qualified Effectful.State as E
1717import qualified Effectful.State.Dynamic as DE
bench/FileSizes.hs+1−2
@@ -10,8 +10,7 @@ import Data.Tuple
1010import System.Posix
1111
1212-- effectful
13−import qualified Effectful.Interpreter as E
14−import qualified Effectful.Monad as E
13+import qualified Effectful as E
1514import qualified Effectful.Reader as E
1615import qualified Effectful.State as E
1716
effectful.cabal+2−1
@@ -67,7 +67,8 @@ library
6767
6868 hs-source-dirs: src
6969
70− exposed-modules: Effectful.Async
70+ exposed-modules: Effectful
71+ Effectful.Async
7172 Effectful.Class.Reader
7273 Effectful.Class.State
7374 Effectful.Class.Writer
examples/FileSystem.hs+1−2
@@ -14,9 +14,8 @@ import Prelude hiding (readFile, writeFile)
1414import qualified Data.Map.Strict as M
1515import qualified System.IO as IO
1616
17+import Effectful
1718import Effectful.Error
18−import Effectful.Interpreter
19−import Effectful.Monad
2019import Effectful.State
2120
2221-- | An effect for reading and writing files.
src/Effectful.hsnew file+35
@@ -0,0 +1,35 @@
1+module Effectful
2+ ( -- * The 'Eff' monad
3+ Eff
4+
5+ -- ** Effect constraints
6+ , Effect
7+ , (:>)
8+
9+ -- * Sending effects
10+ , send
11+
12+ -- * Running the 'Eff' monad
13+
14+ -- ** Pure operations
15+ , runEff
16+
17+ -- ** Operations with side effects
18+ , IOE
19+ , runIOE
20+
21+ -- * Building 'Effect' handlers
22+
23+ -- ** Basic handlers
24+ , interpret
25+ , interpretM
26+ , interpretIO
27+
28+ -- ** Derived handlers
29+ , reinterpret
30+ , reinterpretM
31+ , reinterpretIO
32+ ) where
33+
34+import Effectful.Interpreter
35+import Effectful.Monad
src/Effectful/Internal/Effect.hs+12
@@ -14,12 +14,24 @@ module Effectful.Internal.Effect
1414import Data.Kind
1515import GHC.TypeLits
1616
17+-- | The kind of effects.
1718type Effect = (Type -> Type) -> Type -> Type
1819
1920-- | Adapter for statically dispatched effects.
2021newtype IdE (e :: Effect) where
2122 IdE :: (forall m r. e m r) -> IdE e
2223
24+-- | A constraint that requires that a particular effect, @e@, is a member of
25+-- the type-level list @es@. This is used to parameterize an
26+-- 'Effectful.Monad.Eff' operation over an arbitrary list of effects, so long as
27+-- @e@ is /somewhere/ in the list.
28+--
29+-- For example, an operation that only needs access to a cell of mutable state
30+-- containing an 'Integer' would likely use the following type:
31+--
32+-- @
33+-- 'Effectful.State.State' 'Integer' ':>' es => 'Effectful.Monad.Eff' es ()
34+-- @
2335class (e :: Effect) :> (es :: [Effect]) where
2436 -- | Get the position of @e@ in @es@.
2537 --
src/Effectful/Internal/Monad.hs+27−3
@@ -59,6 +59,30 @@ import Effectful.Internal.Env
5959
6060type role Eff nominal representational
6161
62+-- | The 'Eff' monad provides the implementation of an operation that performs
63+-- an arbitrary set of effects. In @'Eff' es a@, @es@ is a type-level list that
64+-- contains all the effects that the operation may perform. For example, an
65+-- operation that produces an 'Integer' by consuming a 'String' from the global
66+-- environment and acting upon a single mutable cell containing a 'Bool' would
67+-- have the following type:
68+--
69+-- @
70+-- 'Eff' '['Effectful.Reader.Reader' 'String', 'Effectful.State.State' 'Bool'] 'Integer'
71+-- @
72+--
73+-- Normally, a concrete list of effects is not used to parameterize 'Eff'.
74+-- Instead, the '(:>)' class is used to express constraints on the list of
75+-- effects without coupling an operation to a concrete list of effects. For
76+-- example, the above example would more commonly be expressed with the
77+-- following type:
78+--
79+-- @
80+-- ('Effectful.Reader.Reader' 'String' ':>' es, 'Effectful.State.State' 'Bool' ':>' es) => 'Eff' es 'Integer'
81+-- @
82+--
83+-- This abstraction allows the operation to be used in functions that may
84+-- perform other effects, and it also allows the effects to be handled in any
85+-- order.
6286newtype Eff (es :: [Effect]) a = Eff (Env es -> IO a)
6387
6488-- | Run a pure 'Eff' operation.
@@ -220,12 +244,12 @@ tryFailIO tag m =
220244----------------------------------------
221245-- IO
222246
223−-- | Run 'IO' operations via 'MonadIO', 'MonadBaseControl' 'IO' and
224−-- 'MonadUnliftIO' classes.
247+-- | Run arbitrary 'IO' operations via 'MonadIO', 'MonadBaseControl' 'IO' or
248+-- 'MonadUnliftIO'.
225249data IOE :: Effect where
226250 IOE :: IOE m r
227251
228−-- | Run an impure 'Eff' operation.
252+-- | Run an 'Eff' operation with side effects.
229253--
230254-- For the pure version see 'runEff'.
231255runIOE :: Eff '[IOE] a -> IO a
src/Effectful/Interpreter.hs+3
@@ -50,6 +50,9 @@ runInterpreter es0 e m = do
5050-- Sending commands
5151
5252-- | Send an operation of a given effect to the interpreter.
53+--
54+-- This is used to connect the definition of an effect to the 'Eff' monad so
55+-- that it can be used and handled.
5356send :: (HasCallStack, e :> es) => e (Eff es) a -> Eff es a
5457send op = readerEffectM $ \Interpreter{..} -> do
5558 unsafeUnliftEff $ \run -> unEff (_interpret run op) _env
src/Effectful/State/Dynamic.hs+1−3
@@ -33,10 +33,8 @@ module Effectful.State.Dynamic
3333 , modifyM
3434 ) where
3535
36−import Effectful.Internal.Effect
37−import Effectful.Internal.Monad
3836import Effectful.Interpreter
39−
37+import Effectful.Monad
4038import qualified Effectful.State as SP
4139import qualified Effectful.State.MVar as SM
4240
src/Effectful/Writer/Dynamic.hs+1−3
@@ -15,10 +15,8 @@ module Effectful.Writer.Dynamic
1515 , listens
1616 ) where
1717
18−import Effectful.Internal.Effect
19−import Effectful.Internal.Monad
2018import Effectful.Interpreter
21−
19+import Effectful.Monad
2220import qualified Effectful.Writer as WP
2321import qualified Effectful.Writer.MVar as WM
2422
tests/AsyncTests.hs+1−1
@@ -7,10 +7,10 @@ import Test.Tasty
77import Test.Tasty.HUnit
88import qualified Data.Set as S
99
10+import Effectful
1011import Effectful.Async
1112import Effectful.Error
1213import Effectful.State.Dynamic
13−import Effectful.Monad
1414
1515import qualified Utils as U
1616
tests/ErrorTests.hs+1−2
@@ -5,9 +5,8 @@ import Test.Tasty
55import Test.Tasty.HUnit
66import GHC.Stack (getCallStack)
77
8+import Effectful
89import Effectful.Error
9−import Effectful.Interpreter
10−import Effectful.Monad
1110
1211errorTests :: TestTree
1312errorTests = testGroup "Error"
tests/StateTests.hs+1−2
@@ -6,9 +6,8 @@ import qualified Control.Monad.Catch as E
66import qualified Control.Exception.Lifted as LE
77import qualified UnliftIO.Exception as UE
88
9−import Effectful.Interpreter
9+import Effectful
1010import Effectful.State.Dynamic
11−import Effectful.Monad
1211import qualified Utils as U
1312
1413stateTests :: TestTree
tests/Utils.hs+1−1
@@ -10,7 +10,7 @@ import Control.Monad.IO.Class
1010import GHC.Stack
1111import qualified Test.Tasty.HUnit as T
1212
13−import Effectful.Monad
13+import Effectful
1414
1515assertBool :: (HasCallStack, IOE :> es) => String -> Bool -> Eff es ()
1616assertBool msg p = liftIO $ T.assertBool msg p