packages feed

simple-effects 0.6.0.1 → 0.6.0.2

raw patch · 10 files changed

+353/−61 lines, 10 filesdep +arraydep −ghc-prim

Dependencies added: array

Dependencies removed: ghc-prim

Files

bench/Bench.hs view
@@ -1,24 +1,27 @@ {-# LANGUAGE FlexibleContexts, TypeApplications #-}
-import Interlude
+import Interlude hiding (modify', execStateT)
 
-import GHC.IO.Encoding (setLocaleEncoding, utf16)
-import Control.Effects
-import Control.Effects.State hiding (mtlSimple, effectsSimple)
+import GHC.IO.Encoding (setLocaleEncoding, utf8)
+import Control.Effects.State
 
+import Control.Monad.State.Strict
+import Control.Monad.Trans.State.Strict (execStateT)
+
 import Criterion.Main
 
 mtlSimple :: MonadState Int m => m ()
 mtlSimple = replicateM_ 1000000 mtlSimple'
     where mtlSimple' = modify' (+ 1)
 
-effectsSimple :: (MonadEffect (GetState Int) m, MonadEffect (SetState Int) m) => m ()
+effectsSimple :: (MonadEffectState Int m) => m ()
 effectsSimple = replicateM_ 1000000 effectsSimple'
     where effectsSimple' = modifyState (+ (1 :: Int))
 
 main :: IO ()
-main =
+main = do
+    setLocaleEncoding utf8
     defaultMain
         [ bench "MTL state" $ nfIO (execStateT mtlSimple 0)
         , bench "Effects state" $ nfIO effState
         ]
-    where effState = handleStateIO @_ @Int @Int 0 (effectsSimple >> getState)
+    where effState = handleStateT (0 :: Int) (effectsSimple >> getState @Int)
simple-effects.cabal view
@@ -1,5 +1,5 @@ name:                simple-effects
-version:             0.6.0.1
+version:             0.6.0.2
 synopsis:            A simple effect system that integrates with MTL
 description:         Please see README.md
 homepage:            https://gitlab.com/LukaHorvat/simple-effects
@@ -20,6 +20,8 @@                      , Control.Effects.List
                      , Control.Effects.Signal
                      , Control.Effects.Early
+                     , Control.Effects.Parallel
+                     , Control.Monad.Runnable
   hs-source-dirs:      src
   default-language:    Haskell2010
   build-depends:       base >= 4.7 && < 5
@@ -30,7 +32,7 @@                      , transformers-base == 0.4.*
                      , list-t
                      , lens
-                     , ghc-prim
+                     , array
   default-extensions:  NoImplicitPrelude
   ghc-options:         -Wall
 
@@ -42,7 +44,7 @@     build-depends:     base >= 4.7 && < 5
                      , simple-effects
                      , interlude-l >= 0.1.0.6
-    ghc-options:       -Wall
+    ghc-options:       -Wall -threaded -with-rtsopts=-N
     default-extensions:NoImplicitPrelude
 
 benchmark bench-effects
src/Control/Effects.hs view
@@ -9,6 +9,7 @@ import Control.Monad.Trans.Control
 import Control.Monad.Base
 
+import Control.Monad.Runnable
 import Control.Effects1
 
 type family EffectMsg eff :: *
@@ -22,18 +23,26 @@ --   handle the effect.
 newtype EffectHandler eff m a = EffectHandler
     { unpackEffectHandler :: ReaderT (EffectMsg eff -> m (EffectRes eff)) m a }
-    deriving (Functor, Applicative, Monad, MonadState s, MonadIO, MonadCatch, MonadThrow, MonadRandom)
+    deriving ( Functor, Applicative, Monad, Alternative, MonadState s, MonadIO, MonadCatch
+             , MonadThrow, MonadRandom )
 
 instance MonadTrans (EffectHandler eff) where
     lift = EffectHandler . lift
 
+instance RunnableTrans (EffectHandler eff) where
+    type TransformerState (EffectHandler eff) m = EffectMsg eff -> m (EffectRes eff)
+    type TransformerResult (EffectHandler eff) m a = a
+    currentTransState = EffectHandler ask
+    restoreTransState = return
+    runTransformer m = runReaderT (unpackEffectHandler m)
+
 instance MonadReader s m => MonadReader s (EffectHandler eff m) where
     ask = EffectHandler (lift ask)
     local f (EffectHandler rdr) = EffectHandler (ReaderT $ local f . runReaderT rdr)
 
-deriving instance MonadBase IO m => MonadBase IO (EffectHandler eff m)
+deriving instance MonadBase b m => MonadBase b (EffectHandler eff m)
 
-instance MonadBaseControl IO m => MonadBaseControl IO (EffectHandler eff m) where
+instance MonadBaseControl b m => MonadBaseControl b (EffectHandler eff m) where
     type StM (EffectHandler eff m) a = StM (ReaderT (EffectMsg eff -> m (EffectRes eff)) m) a
     liftBaseWith f = EffectHandler $ liftBaseWith $ \q -> f (q . unpackEffectHandler)
     restoreM = EffectHandler . restoreM
src/Control/Effects/Early.hs view
@@ -1,5 +1,7 @@ {-# LANGUAGE RankNTypes, TypeFamilies, FlexibleContexts, ScopedTypeVariables, MultiParamTypeClasses #-}
-module Control.Effects.Early (module Control.Effects, Early, earlyReturn, handleEarly) where
+module Control.Effects.Early
+    ( module Control.Effects, Early
+    , earlyReturn, handleEarly, onlyDo, ifNothingEarlyReturn, ifNothingDo ) where
 
 import Interlude
 import Control.Monad.Trans.Except
@@ -26,3 +28,17 @@ handleEarly :: Monad m => ExceptT a m a -> m a
 handleEarly = fmap collapseEither
             . runExceptT
+
+-- | Only do the given action and exit early with it's result.
+onlyDo :: MonadEffect (Early a) m => m a -> m b
+onlyDo m = m >>= earlyReturn
+
+-- | Early return the given value if the 'Maybe' is 'Nothing'. Otherwise, contnue with the value
+--   inside of it.
+ifNothingEarlyReturn :: MonadEffect (Early a) m => a -> Maybe b -> m b
+ifNothingEarlyReturn a = maybe (earlyReturn a) return
+
+-- | Only do the given action and early return with it's result if the given value is 'Nothing'.
+--   Otherwise continue with the value inside of the 'Maybe'.
+ifNothingDo :: MonadEffect (Early a) m => m a -> Maybe b -> m b
+ifNothingDo m = maybe (onlyDo m) return
+ src/Control/Effects/Parallel.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE ScopedTypeVariables, FlexibleContexts #-}
+module Control.Effects.Parallel where
+
+import Interlude hiding (toList)
+
+import GHC.IO.Unsafe
+import Data.Array.IO
+
+import Control.Monad.Runnable
+import Control.Effects.State
+
+forkThread :: IO () -> IO (MVar ())
+forkThread proc = do
+    h <- newEmptyMVar
+    _ <- forkFinally proc (\_ -> putMVar h ())
+    return h
+
+appendState :: forall s m a proxy. (Semigroup s, MonadEffectState s m)
+            => proxy s -> m a -> m a
+appendState _ m = do
+    s :: s <- getState
+    a <- m
+    s' :: s <- getState
+    setState (s <> s')
+    return a
+
+parallelWithRestore :: forall m a. Runnable m => (m a -> m a) -> [m a] -> m [a]
+parallelWithRestore combine tasks = do
+    ress <- parallel tasks
+    mapM (combine . restoreMonadicState) ress
+
+parallelWithSequence :: Runnable m => [m a] -> m [a]
+parallelWithSequence = mapM restoreMonadicState <=< parallel
+
+parallel :: forall m a. Runnable m => [m a] -> m [MonadicResult m a]
+parallel tasks = do
+    st <- currentMonadicState
+    let ress = unsafePerformIO $ do
+            arr :: IOArray Int (MonadicResult m a) <- newArray_ (0, n - 1)
+            threads <- forM (zip [0..] tasks) $ \(i, t) -> forkThread $ do
+                res <- runMonad st t
+                writeArray arr i res
+            mapM_ takeMVar threads
+            getElems arr
+    ress `seq` return ress
+    where n = length tasks
src/Control/Effects/Signal.hs view
@@ -14,7 +14,7 @@ import qualified GHC.TypeLits as TL
 import GHC.TypeLits (TypeError, ErrorMessage(..))
 import Control.Effects
-import Control.Monad.Trans.Control
+import Control.Monad.Runnable
 
 data Signal a b
 type instance EffectMsg (Signal a b) = a
@@ -118,7 +118,7 @@ showAllExceptions = fmap (mapLeft getSomeSignal) . runExceptT
 
 -- | A class of monads that throw and catch exceptions of type @e@. An overlappable instance is
---   given so you just need to make sure your transformers have a 'MonadTransControl' instance.
+--   given so you just need to make sure your transformers have a 'RunnableTrans' instance.
 class Throws e m => Handles e m where
     -- | Use this function to handle exceptions without discarding the 'Throws' constraint.
     --   You'll want to use this if you're writing a recursive function. Using the regular handlers
@@ -150,11 +150,12 @@     handleRecursive f = ExceptT . (either (runExceptT . f) (return . Right) <=< runExceptT)
     {-# INLINE handleRecursive #-}
 
-instance {-# OVERLAPPABLE #-} (Monad m, Monad (t m), Handles e m, MonadTransControl t)
+instance {-# OVERLAPPABLE #-} (Monad m, Monad (t m), Handles e m, RunnableTrans t)
          => Handles e (t m) where
     handleRecursive f e = do
-        st <- liftWith (\run -> handleRecursive (run . f) (run e))
-        restoreT (return st)
+        st <- currentTransState
+        res <- lift (handleRecursive (\ex -> runTransformer (f ex) st) (runTransformer e st))
+        restoreTransState res
     {-# INLINE handleRecursive #-}
 
 -- | 'handleToEither' that doesn't discard 'Throws' constraints. See documentation for
src/Control/Effects/State.hs view
@@ -1,61 +1,68 @@ {-# LANGUAGE TypeFamilies, ScopedTypeVariables, FlexibleContexts, Rank2Types, ConstraintKinds #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-module Control.Effects.State (module Control.Effects.State, module Control.Effects) where
+{-# LANGUAGE MultiParamTypeClasses, GADTs, BangPatterns #-}
+module Control.Effects.State (module Control.Effects.State, module Control.Effects1) where
 
-import Interlude
+import Interlude hiding (Set, State)
 
 import Data.IORef
 
-import Control.Effects
-
-data GetState s
-data SetState s
+import Control.Effects1
 
-type instance EffectMsg (GetState s) = ()
-type instance EffectRes (GetState s) = s
+data State s
+data Get
+data Set
+data StateMessage s a where
+    GetMessage :: StateMessage s Get
+    SetMessage :: !s -> StateMessage s Set
+data StateResult s a where
+    GetResult :: { getGetResult :: !s } -> StateResult s Get
+    SetResult :: StateResult s Set
 
-type instance EffectMsg (SetState s) = s
-type instance EffectRes (SetState s) = ()
+type instance EffectMsg1 (State s) = StateMessage s
+type instance EffectRes1 (State s) = StateResult s
+type instance EffectCon1 (State s) a = ()
 
-instance Monad m => MonadEffect (GetState s) (StateT s m) where
-    effect _ _ = get
+instance Monad m => MonadEffect1 (State s) (StateT s m) where
+    effect1 _ GetMessage = GetResult <$> get
+    effect1 _ (SetMessage s) = SetResult <$ put s
+    {-# INLINE effect1 #-}
 
-instance Monad m => MonadEffect (SetState s) (StateT s m) where
-    effect _ = put
+type MonadEffectState s m = MonadEffect1 (State s) m
 
-type MonadEffectState s m = (MonadEffect (GetState s) m, MonadEffect (SetState s) m)
-type EffectHandlerState s m = EffectHandler (GetState s) (EffectHandler (SetState s) m)
+stateEffect :: forall s a m. MonadEffectState s m
+            => StateMessage s a -> m (StateResult s a)
+stateEffect = effect1 (Proxy :: Proxy (State s))
+{-# INLINE stateEffect #-}
 
-getState :: forall s m. MonadEffect (GetState s) m => m s
+getState :: forall s m. MonadEffectState s m => m s
+getState = getGetResult <$> stateEffect GetMessage
 {-# INLINE getState #-}
-getState = effect (Proxy :: Proxy (GetState s)) ()
 
-setState :: forall s m. MonadEffect (SetState s) m => s -> m ()
+setState :: forall s m. MonadEffectState s m => s -> m ()
+setState s = void $ stateEffect (SetMessage s)
 {-# INLINE setState #-}
-setState = effect (Proxy :: Proxy (SetState s))
 
 modifyState :: forall s m. MonadEffectState s m => (s -> s) -> m ()
+modifyState f = do
+    s <- getState
+    let s' = f s in s' `seq` setState s'
 {-# INLINE modifyState #-}
-modifyState f = setState . f =<< getState
 
-handleGetState :: m s -> EffectHandler (GetState s) m a -> m a
-{-# INLINE handleGetState #-}
-handleGetState = handleEffect . const
-
-handleSetState :: (s -> m ()) -> EffectHandler (SetState s) m a -> m a
-{-# INLINE handleSetState #-}
-handleSetState = handleEffect
-
-handleState :: Monad m => m s -> (s -> m ()) -> EffectHandlerState s m a -> m a
+handleState :: forall m s a. Monad m => m s -> (s -> m ())
+            -> EffectHandler1 (State s) m a -> m a
+handleState getter setter =
+    handleEffect1 handler
+    where handler :: forall b. StateMessage s b -> m (StateResult s b)
+          handler GetMessage = GetResult <$> getter
+          handler (SetMessage s) = SetResult <$ setter s
 {-# INLINE handleState #-}
-handleState getter setter = handleSetState setter . handleGetState (lift getter)
 
-handleStateIO :: MonadIO m => s -> EffectHandlerState s m a -> m a
-{-# INLINE handleStateIO #-}
+handleStateIO :: MonadIO m => s -> EffectHandler1 (State s) m a -> m a
 handleStateIO initial m = do
     ref <- liftIO (newIORef initial)
     m & handleState (liftIO (readIORef  ref)) (liftIO . writeIORef ref)
+{-# INLINE handleStateIO #-}
 
 handleStateT :: Monad m => s -> StateT s m a -> m a
-{-# INLINE handleStateT #-}
 handleStateT = flip evalStateT
+{-# INLINE handleStateT #-}
src/Control/Effects1.hs view
@@ -9,6 +9,8 @@ import Control.Monad.Trans.Control
 import Control.Monad.Base
 
+import Control.Monad.Runnable
+
 type family EffectMsg1 eff :: * -> *
 type family EffectRes1 eff :: * -> *
 type family EffectCon1 eff a :: Constraint
@@ -24,10 +26,18 @@ --   handle the effect.
 newtype EffectHandler1 eff m a = EffectHandler1
     { unpackEffectHandler1 :: ReaderT (EffHandling1 eff m) m a }
-    deriving (Functor, Applicative, Monad, MonadState s, MonadIO, MonadCatch, MonadThrow, MonadRandom)
+    deriving ( Functor, Applicative, Monad, Alternative, MonadState s, MonadIO, MonadCatch
+             , MonadThrow, MonadRandom )
 
 instance MonadTrans (EffectHandler1 eff) where
     lift = EffectHandler1 . lift
+
+instance RunnableTrans (EffectHandler1 eff) where
+    type TransformerState (EffectHandler1 eff) m = EffHandling1 eff m
+    type TransformerResult (EffectHandler1 eff) m a = a
+    currentTransState = EffectHandler1 ask
+    restoreTransState = return
+    runTransformer m = runReaderT (unpackEffectHandler1 m)
 
 instance MonadReader s m => MonadReader s (EffectHandler1 eff m) where
     ask = EffectHandler1 (lift ask)
+ src/Control/Monad/Runnable.hs view
@@ -0,0 +1,180 @@+{-# LANGUAGE TypeFamilies, UndecidableInstances, ScopedTypeVariables, FlexibleInstances #-}
+{-# LANGUAGE ExistentialQuantification #-}
+{-# OPTIONS_GHC -Wno-warnings-deprecations #-}
+module Control.Monad.Runnable where
+
+import Interlude hiding (toList, throwError)
+
+import ListT
+import qualified Control.Monad.Trans.State.Strict as SS
+import qualified Control.Monad.Trans.State.Lazy as LS
+import qualified Control.Monad.Trans.Writer.Strict as SW
+import qualified Control.Monad.Trans.Writer.Lazy as LW
+import qualified Control.Monad.Trans.RWS.Strict as SR
+import qualified Control.Monad.Trans.RWS.Lazy as LR
+import Control.Monad.Trans.Identity
+import Control.Monad.Trans.Error
+import Control.Monad.Trans.Except
+import Control.Monad.Trans.Maybe
+-- import Control.Monad.Trans.Cont -- may be impossible to write
+
+-- | A class of monads that have a run function.
+--
+--   The 'runMonad' function gives the result inside of IO. The only reason for this is to allow
+--   an instance for IO to be written. Other instances do not perform any aditional IO.
+--
+--   Instances for 'Identity', 'IO' and
+--   @('Runnable' m, 'RunnableTrans' t, 'Monad' (t m)) => 'Runnable' (t m)@ are given so users
+--   should only provide additional 'RunnableTrans' instances instead of 'Runnable' ones.
+class Monad m => Runnable m where
+    -- | The type of value that needs to be provided to run this monad.
+    type MonadicState m :: *
+    -- | The type of the result you get when you run this monad.
+    type MonadicResult m a :: *
+    -- | Get the current state value.
+    currentMonadicState :: m (MonadicState m)
+    -- | If given a result, reconstruct a monadic compitation.
+    restoreMonadicState :: MonadicResult m a -> m a
+    -- | Given the required state value and a computation, run the computation up to the IO effect.
+    --   This should effectively run each layer in the transformer stack. The 'MonadicState' should
+    --   hold all the needed information to do so.
+    --
+    --   A more formal description of what it means to run a transformer is given for the
+    --   'runTransformer' function.
+    runMonad :: MonadicState m -> m a -> IO (MonadicResult m a)
+
+-- | A class of transformers that can run their effects in the underlying monad.
+--
+--   The following laws need to hold.
+--
+-- @
+--   \t -> do st <- 'currentTransState'
+--            res <- 'lift' ('runTransformer' t st)
+--            'restoreTransState' res
+--   == 'id'
+-- @
+--
+-- @
+--   f :: (forall a. m a -> m a)
+--   \m s -> runTransformer (lift (f m)) s == \m s -> f (runTransformer (lift m) s)
+-- @
+class MonadTrans t => RunnableTrans t where
+    -- | The type of value that needs to be provided to run this transformer.
+    type TransformerState t (m :: * -> *) :: *
+    -- | The type of the result you get when you run this transformer.
+    type TransformerResult t (m :: * -> *) a :: *
+    -- | Get the current state value.
+    currentTransState :: Monad m => t m (TransformerState t m)
+    -- | If given a result, reconstruct the compitation.
+    restoreTransState :: Monad m => TransformerResult t m a -> t m a
+    -- | Given the required state value and a computation, run the effects of the transformer
+    --   in the underlying monad.
+    runTransformer :: Monad m => t m a -> TransformerState t m -> m (TransformerResult t m a)
+
+instance Runnable Identity where
+    type MonadicState Identity = ()
+    type MonadicResult Identity a = a
+    currentMonadicState = return ()
+    restoreMonadicState = return
+    runMonad _ (Identity a) = return a
+
+instance Runnable IO where
+    type MonadicState IO = ()
+    type MonadicResult IO a = a
+    currentMonadicState = return ()
+    restoreMonadicState = return
+    runMonad _ m = m
+
+instance (Runnable m, RunnableTrans t, Monad (t m)) => Runnable (t m) where
+    type MonadicState (t m) = (TransformerState t m, MonadicState m)
+    type MonadicResult (t m) a = MonadicResult m (TransformerResult t m a)
+    currentMonadicState = (,) <$> currentTransState <*> lift currentMonadicState
+    restoreMonadicState s = lift (restoreMonadicState s) >>= restoreTransState
+    runMonad (s, s') t = runMonad s' (runTransformer t s)
+
+instance RunnableTrans (SS.StateT s) where
+    type TransformerState (SS.StateT s) m = s
+    type TransformerResult (SS.StateT s) m a = (a, s)
+    currentTransState = get
+    restoreTransState (a, s) = put s >> return a
+    runTransformer = SS.runStateT
+
+instance RunnableTrans (LS.StateT s) where
+    type TransformerState (LS.StateT s) m = s
+    type TransformerResult (LS.StateT s) m a = (a, s)
+    currentTransState = get
+    restoreTransState (a, s) = put s >> return a
+    runTransformer = LS.runStateT
+
+instance Monoid s => RunnableTrans (SW.WriterT s) where
+    type TransformerState (SW.WriterT s) m = ()
+    type TransformerResult (SW.WriterT s) m a = (a, s)
+    currentTransState = return ()
+    restoreTransState (a, s) = SW.tell s >> return a
+    runTransformer m _ = SW.runWriterT m
+
+instance Monoid s => RunnableTrans (LW.WriterT s) where
+    type TransformerState (LW.WriterT s) m = ()
+    type TransformerResult (LW.WriterT s) m a = (a, s)
+    currentTransState = return ()
+    restoreTransState (a, s) = LW.tell s >> return a
+    runTransformer m _ = LW.runWriterT m
+
+instance RunnableTrans (ReaderT s) where
+    type TransformerState (ReaderT s) m = s
+    type TransformerResult (ReaderT s) m a = a
+    currentTransState = ask
+    restoreTransState = return
+    runTransformer = runReaderT
+
+instance Monoid w => RunnableTrans (SR.RWST r w s) where
+    type TransformerState (SR.RWST r w s) m = (r, s)
+    type TransformerResult (SR.RWST r w s) m a = (a, s, w)
+    currentTransState = (,) <$> ask <*> get
+    restoreTransState (a, s, w) = SR.tell w >> put s >> return a
+    runTransformer m (r, s) = SR.runRWST m r s
+
+instance Monoid w => RunnableTrans (LR.RWST r w s) where
+    type TransformerState (LR.RWST r w s) m = (r, s)
+    type TransformerResult (LR.RWST r w s) m a = (a, s, w)
+    currentTransState = (,) <$> ask <*> get
+    restoreTransState (a, s, w) = LR.tell w >> put s >> return a
+    runTransformer m (r, s) = LR.runRWST m r s
+
+instance RunnableTrans IdentityT where
+    type TransformerState IdentityT m = ()
+    type TransformerResult IdentityT m a = a
+    currentTransState = return ()
+    restoreTransState = return
+    runTransformer m () = runIdentityT m
+
+instance Error e => RunnableTrans (ErrorT e) where
+    type TransformerState (ErrorT e) m = ()
+    type TransformerResult (ErrorT e) m a = Either e a
+    currentTransState = return ()
+    restoreTransState (Left e) = throwError e
+    restoreTransState (Right a) = return a
+    runTransformer m () = runErrorT m
+
+instance RunnableTrans (ExceptT e) where
+    type TransformerState (ExceptT e) m = ()
+    type TransformerResult (ExceptT e) m a = Either e a
+    currentTransState = return ()
+    restoreTransState (Left e) = throwE e
+    restoreTransState (Right a) = return a
+    runTransformer m () = runExceptT m
+
+instance RunnableTrans MaybeT where
+    type TransformerState MaybeT m = ()
+    type TransformerResult MaybeT m a = Maybe a
+    currentTransState = return ()
+    restoreTransState Nothing = mzero
+    restoreTransState (Just a) = return a
+    runTransformer m () = runMaybeT m
+
+instance RunnableTrans ListT where
+     type TransformerState ListT m = ()
+     type TransformerResult ListT m a = [a]
+     currentTransState = return ()
+     restoreTransState = fromFoldable
+     runTransformer m _ = toList m
test/Main.hs view
@@ -1,10 +1,11 @@-{-# LANGUAGE NoMonomorphismRestriction, FlexibleContexts, ScopedTypeVariables #-}
+{-# LANGUAGE NoMonomorphismRestriction, FlexibleContexts, ScopedTypeVariables, BangPatterns #-}
 module Main where
 
 import Interlude
 
 import Control.Effects.Signal
 import Control.Effects.State
+import Control.Effects.Parallel
 
 -- Should infer
 ex1 = signal True
@@ -14,24 +15,41 @@ ex2 = throwSignal False
 
 ex3 = do
-    discardAllExceptions ex1
-    showAllExceptions ex2
-    handleException (\(b :: Bool) -> return ()) ex2
+    void $ discardAllExceptions ex1
+    void $ showAllExceptions ex2
+    handleException (\(_ :: Bool) -> return ()) ex2
     handleSignal (\(_ :: Bool) -> Resume 5) ex1
 
-orderTest :: (Test Bool m, MonadEffectState Int m, MonadIO m) => m ()
+orderTest :: (Handles Bool m, MonadEffectState Int m, MonadIO m) => m ()
 orderTest = do
     setState (1 :: Int)
-    _ :: Either Bool () <- handleE $ do
+    _ :: Either Bool () <- handleToEitherRecursive $ do
         setState (2 :: Int)
         void $ throwSignal True
         setState (3 :: Int)
     st :: Int <- getState
     print st
 
+inc :: Int -> Int
+inc !x = x + 1
+
+task :: (MonadEffectState Int m, MonadIO m) => m Int
+task = do
+    replicateM_ 10000000 (modifyState inc)
+    st <- getState
+    st `seq` return st
+
 main :: IO ()
 main = do
     orderTest & handleException (\(_ :: Bool) -> return ())
               & handleStateT (0 :: Int)
     orderTest & handleStateT (0 :: Int)
               & handleException (\(_ :: Bool) -> return ())
+    putStrLn "Starting sequential test"
+    replicateM_ 8 (handleStateT (0 :: Int) task >>= print)
+    putStrLn "Sequential test done"
+    putStrLn "Starting parallel test"
+    handleStateT (0 :: Int) $ do
+        res <- parallelWithSequence (replicate 8 task)
+        mapM_ print res
+    putStrLn "Parallel test done"