diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,14 @@
+# 0.13.0.0
+* Support for unique parametrized effects.
+    * Each effect can provide an extra constrain on the monad in which it executes
+    * One of the applications is a class that provides an extra functional dependency on some of the effects parameters
+* State effect now has a functional dependency on the parameter meaning you can only have one state effect in a computation, but the inferrence is much better
+* Module for working with newtypes of effects
+    * Allows you to tag a certain effect with a new name so multiples of the same effect can be used without interaction
+    * This lets you recover the ability to use multiple state effects in the same computation
+* Yield effect also gets a functional dependency
+* Async effect gets a parameter with a functional dependency enabling different implementations to use different thread representations
+* Removed Parallel module. Pretty much covered by Async
+* Ability to cancel thread and check if they're done with Async
+* Better errors when failing to derive an Effect instance
+* Better docs
diff --git a/simple-effects.cabal b/simple-effects.cabal
--- a/simple-effects.cabal
+++ b/simple-effects.cabal
@@ -1,7 +1,101 @@
 name:                simple-effects
-version:             0.12.0.0
+version:             0.13.0.0
 synopsis:            A simple effect system that integrates with MTL
-description:         Please see the tutorial modules
+description:
+    Some of the things you can do with this package:
+    .
+    * Declare and check which side-effects your function uses
+    * Dependency injection
+    * Test effectful code
+    * Avoid the \(n \times k\) instance problem
+    * Define custom effects with very little programming overhead
+    .
+    === Declare and check which side-effects your function uses
+    .
+    The library provides a nice, declarative way of specifying exactly what your monadic function
+    does.
+    .
+    > getProductAndWriteToFile :: MonadEffects '[Database, FileSystem] m => ProductId -> FilePath -> m ()
+    .
+    This way you can be sure that your @harmlessFunction@ doesn't do unexpected things behind your
+    back. The compiler makes sure that all the effects are accounted for in the function's type.
+    .
+    === Dependency injection
+    .
+    Functions are not tied to any specific implementation of an effect meaning you can swap out
+    different implementations without changing your code. Code like this
+    .
+    > myFunction :: MonadEffects '[Time, Logging] m => m ()
+    > myFunction = do
+    >     t <- getCurrentTime
+    >     log (show t)
+    .
+    is effectively the same as
+    .
+    > myFunction :: Monad m => m ZonedTime -> (String -> m ()) -> m ()
+    > myFunction getCurrentTime log = do
+    >     t <- getCurrentTime
+    >     log (show t)
+    .
+    but the library does all the parameter passing for you. And just like you'd be able to
+    provide any implementation as @getCurrentTime@ and @log@ parameters you can do the same with
+    simple effects.
+    .
+    > myFunction
+    >     & implement (TimeMethods someCurrentTimeImplementation)
+    >     & implement (LoggingMethods someLoggingImplementation)
+    .
+    === Test effectful code
+    .
+    Easily provide dummy implementations of your effects to prevent missle-launching during testing.
+    .
+    > myEffectfulFunction :: MonadEffects '[Database, Missiles] m => m Int
+    >
+    > main = do
+    >     conn <- connectToDb "connStr"
+    >     myEffectfulFunction
+    >         & implement (realDatabase conn)
+    >         & implement (MissilesMethods (launchMissles "access codes"))
+    >
+    > spec = do
+    >     res <- myEffectfulFunction
+    >         & implement (fakeDb Map.empty)
+    >         & implement (MissilesMethods (print "Totally launching missiles"))
+    >     when (res /= 42) (error "Test failed!")
+    .
+    === Avoid the \(n \times k\) instance problem
+    .
+    Any effect you define is automatically liftable through any transformer. Most @MonadX@ instances
+    you'd write would look like @func a b c = lift (func a b c)@, so why would you have to write them
+    yourself? @simple-effects@ does it for you using an overlappable instance.
+    .
+    What about effects that aren't that simple? Each effect can specify a constraint on the transformers
+    that it can be lifted through and a mechanism that does the lifting. So you get all the benefits
+    of automatic lifting of simple effects and retain all of the flexibility of complex ones.
+    .
+    === Define custom effects with very little programming overhead
+    .
+    Lets say we need a way to get coordinates for some address. Here's how we'd declare that
+    functionality.
+    .
+    @
+    data Geolocation m = GeolocationMethods
+    &#32;   &#x7b; _getLocation :: Address -> m Coordinates &#x7d;
+    &#32;   deriving (Generic, Effect)
+    getLocation :: MonadEffect Geolocation m => Address -> m Coordinates
+    getLocation = _getLocation effect
+    @
+    .
+    That's all you need to start using your effect in functions.
+    .
+    > getUsersLocation :: (MonadEffect Geolocation m, MonadIO m) => m Coordinates
+    > getUsersLocation = do
+    >     liftIO $ putStrLn "Please enter your address:"
+    >     addr <- liftIO readLn
+    >     getLocation addr
+    .
+    ==== <Tutorial-T1_Introduction.html Check out the tutorial modules for more details>
+    .
 homepage:            https://gitlab.com/LukaHorvat/simple-effects
 license:             BSD3
 license-file:        LICENSE
@@ -11,6 +105,7 @@
 category:            Control
 build-type:          Simple
 cabal-version:       >=1.10
+extra-source-files:  CHANGELOG.md
 
 library
   exposed-modules:     Control.Effects
@@ -19,11 +114,11 @@
                      , Control.Effects.List
                      , Control.Effects.Signal
                      , Control.Effects.Early
-                     , Control.Effects.Parallel
                      , Control.Effects.Generic
                      , Control.Effects.Async
                      , Control.Effects.Yield
                      , Control.Effects.Resource
+                     , Control.Effects.Newtype
                      , Control.Monad.Runnable
                      , Tutorial.T1_Introduction
                      , Tutorial.T2_Details
diff --git a/src/Control/Effects.hs b/src/Control/Effects.hs
--- a/src/Control/Effects.hs
+++ b/src/Control/Effects.hs
@@ -4,6 +4,7 @@
 {-# LANGUAGE DefaultSignatures #-}
 {-# LANGUAGE StandaloneDeriving, DataKinds #-}
 {-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE UndecidableSuperClasses, FunctionalDependencies, PolyKinds #-}
 module Control.Effects (module Control.Effects) where
 
 import Import hiding (liftThrough)
@@ -14,6 +15,10 @@
 class Effect (e :: (* -> *) -> *) where
     type CanLift e (t :: (* -> *) -> * -> *) :: Constraint
     type CanLift e t = MonadTrans t
+
+    type ExtraConstraint e (m :: * -> *) :: Constraint
+    type ExtraConstraint e m = ()
+
     liftThrough ::
         forall t m. (CanLift e t, Monad m, Monad (t m))
         => e m -> e (t m)
@@ -30,13 +35,13 @@
         => m (e m) -> e m
     mergeContext = genericMergeContext
 
-class (Effect e, Monad m) => MonadEffect e m where
+class (Effect e, Monad m, ExtraConstraint e m) => MonadEffect e m where
     effect :: e m
     default effect :: (MonadEffect e m', Monad (t m'), CanLift e t, t m' ~ m) => e m
     effect = liftThrough effect
 
 instance {-# OVERLAPPABLE #-}
-    (MonadEffect e m, Monad (t m), CanLift e t)
+    (MonadEffect e m, Monad (t m), CanLift e t, ExtraConstraint e (t m))
     => MonadEffect e (t m) where
     effect = liftThrough effect
 
@@ -66,7 +71,7 @@
     restoreTransState = return
     runTransformer (RuntimeImplemented m) = runReaderT m
 
-instance (Effect e, Monad m, CanLift e (RuntimeImplemented e))
+instance (Effect e, Monad m, CanLift e (RuntimeImplemented e), ExtraConstraint e (RuntimeImplemented e m))
     => MonadEffect e (RuntimeImplemented e m) where
     effect = mergeContext $ RuntimeImplemented (liftThrough <$> ask)
 
@@ -76,3 +81,6 @@
 type family MonadEffects effs m :: Constraint where
     MonadEffects '[] m = ()
     MonadEffects (eff ': effs) m = (MonadEffect eff m, MonadEffects effs m)
+
+class UniqueEffect (effName :: k) (m :: * -> *) a | effName m -> a
+instance {-# OVERLAPPABLE #-} UniqueEffect effName m a => UniqueEffect effName (t m) a
diff --git a/src/Control/Effects/Async.hs b/src/Control/Effects/Async.hs
--- a/src/Control/Effects/Async.hs
+++ b/src/Control/Effects/Async.hs
@@ -6,6 +6,7 @@
 {-# LANGUAGE NoMonomorphismRestriction #-}
 {-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE FlexibleInstances #-}
 {-| The 'Async' effect allows you to fork new threads in monads other than just 'IO'.
 -}
 module Control.Effects.Async where
@@ -14,53 +15,49 @@
 import Control.Effects
 import qualified Control.Concurrent.Async as Async
 import Control.Monad.Runnable
+import Data.Maybe
 
-data Async m = AsyncMethods
-    { _async :: forall a. m a -> m (AsyncThread m a)
-    , _waitAsync :: forall a. AsyncThread m a -> m a }
+data Async thread m = AsyncMethods
+    { _async :: forall a. m a -> m (thread m a)
+    , _waitAsync :: forall a. thread m a -> m a
+    , _isAsyncDone :: forall a n. thread n a -> m Bool
+    , _cancelAsync :: forall a n. thread n a -> m () }
 
--- | The type that represents the forked computation in the monad @m@ that eventually computes
---   a value of type @a@. Depending on the monad, the computation may produce zero, one or even
---   multiple values of that type.
-newtype AsyncThread m a = AsyncThread (Async.Async (m a))
-    deriving (Functor, Eq, Ord)
+class ThreadIdentifier thread where
+    mapThread :: (m a -> n b) -> thread m a -> thread n b
 
-instance Effect Async where
-    type CanLift Async t = RunnableTrans t
+instance ThreadIdentifier thread => Effect (Async thread) where
+    type CanLift (Async thread) t = RunnableTrans t
+    type ExtraConstraint (Async thread) m = UniqueEffect Async m thread
     mergeContext mm = AsyncMethods
         (\a -> mm >>= ($ a) . _async)
         (\a -> mm >>= ($ a) . _waitAsync)
-    liftThrough (AsyncMethods f g) = AsyncMethods
+        (\a -> mm >>= ($ a) . _isAsyncDone)
+        (\a -> mm >>= ($ a) . _cancelAsync)
+    liftThrough (AsyncMethods f g h i) = AsyncMethods
         (\tma -> do
             st <- currentTransState
             !res <- lift (f (runTransformer tma st))
-            return $ mapAsync (lift >=> restoreTransState) res
+            return $ mapThread (lift >=> restoreTransState) res
             )
         (\a -> do
             st <- currentTransState
-            res <- lift (g (mapAsync (`runTransformer` st) a))
+            res <- lift (g (mapThread (`runTransformer` st) a))
             restoreTransState res
             )
-        where
-        mapAsync :: (m a -> n b) -> AsyncThread m a -> AsyncThread n b
-        mapAsync f' (AsyncThread as) = AsyncThread (fmap f' as)
-
--- | The 'IO' implementation uses the @async@ library.
-instance MonadEffect Async IO where
-    effect = AsyncMethods
-        (fmap (AsyncThread . fmap return) . Async.async)
-        (\(AsyncThread as) -> join (Async.wait as))
+        (lift . h)
+        (lift . i)
 
 -- | Fork a new thread to run the given computation. The monadic context is forked into the new
 --   thread.
 --
---   For example, if we use state, the current state value will be visible int he forked computation.
+--   For example, if we use state, the current state value will be visible in the forked computation.
 --   Depending on how we ultimately implement the state, modifying it may or may not be visible
 --   from the main thread. If we use 'implementStateViaStateT' then setting the state in the forked
 --   thread will just modify the thread-local value. On the other hand, if we use
 --  'implementStateViaIORef' then both the main thread and the new thread will use the same reference
 --   meaning they can interact through it.
-async :: MonadEffect Async m => m a -> m (AsyncThread m a)
+async :: MonadEffect (Async thread) m => m a -> m (thread m a)
 
 -- | Wait for the thread to finish and return it's result. The monadic context will also be merged.
 --
@@ -73,11 +70,44 @@
 --  'waitAsync' th
 --  print =<< 'getState' \@Int -- Outputs 2
 -- @
-waitAsync :: MonadEffect Async m => AsyncThread m a -> m a
-AsyncMethods async waitAsync = effect
+waitAsync :: MonadEffect (Async thread) m => thread m a -> m a
 
+-- | Check if the asynchronous computation has finished (either normally, or with an exception)
+isAsyncDone :: MonadEffect (Async thread) m => thread n a -> m Bool
+
+-- | Abort the asynchronous exception
+cancelAsync :: MonadEffect (Async thread) m => thread n a -> m ()
+AsyncMethods async waitAsync isAsyncDone cancelAsync = effect
+
+-- | The type that represents the forked computation in the monad @m@ that eventually computes
+--   a value of type @a@. Depending on the monad, the computation may produce zero, one or even
+--   multiple values of that type.
+newtype AsyncThread m a = AsyncThread (Async.Async (m a))
+    deriving (Functor, Eq, Ord)
+instance ThreadIdentifier AsyncThread where
+    mapThread f (AsyncThread as) = AsyncThread (fmap f as)
+
+instance UniqueEffect Async (RuntimeImplemented (Async thread) m) thread
+instance UniqueEffect Async IO AsyncThread
+-- | The 'IO' implementation uses the @async@ library.
+instance MonadEffect (Async AsyncThread) IO where
+    effect = AsyncMethods
+        (fmap (AsyncThread . fmap return) . Async.async)
+        (\(AsyncThread as) -> join (Async.wait as))
+        (\(AsyncThread as) -> isJust <$> Async.poll as)
+        (\(AsyncThread as) -> Async.cancel as)
+
 -- | This will discard the @'MonadEffect' 'Async' m@ constraint by forcing @m@ to be 'IO'.
 --   The functions doesn't actually do anything, the real implementation is given by the
 --   @'MonadEffect' 'Async' IO@ instance which uses the @async@ package.
 implementAsyncViaIO :: IO a -> IO a
 implementAsyncViaIO = id
+
+-- | Like 'mapM' but the supplied function is run in parallel asynchronously on all the elements.
+--   The results will be in the same order as the inputs.
+parallelMapM :: (MonadEffect (Async thread) m, Traversable t) => (a -> m b) -> t a -> m (t b)
+parallelMapM f = mapM waitAsync <=< mapM (async . f)
+
+-- | Same as 'parallelMapM_' but discards the result.
+parallelMapM_ :: (MonadEffect (Async thread) m, Traversable t) => (a -> m b) -> t a -> m ()
+parallelMapM_ f = mapM_ waitAsync <=< mapM (async . f)
diff --git a/src/Control/Effects/Generic.hs b/src/Control/Effects/Generic.hs
--- a/src/Control/Effects/Generic.hs
+++ b/src/Control/Effects/Generic.hs
@@ -1,79 +1,63 @@
-{-# LANGUAGE ScopedTypeVariables, TypeFamilies, PolyKinds, FlexibleInstances #-}
+{-# LANGUAGE ScopedTypeVariables, TypeFamilies, FlexibleInstances #-}
 {-# LANGUAGE UndecidableInstances, TypeOperators, MultiParamTypeClasses #-}
 {-# LANGUAGE TypeApplications, RankNTypes, DataKinds, ViewPatterns #-}
+{-# LANGUAGE EmptyCase, FlexibleContexts, AllowAmbiguousTypes #-}
 {-# OPTIONS_GHC -fno-warn-missing-methods #-}
 module Control.Effects.Generic where
 
 import qualified GHC.Generics as Gen
 import GHC.Generics
 import Control.Monad.Trans
-import Data.Proxy
 import GHC.TypeLits
+import Control.Monad (join)
 
-data M a
 
-class (Generic (a m), Generic (a (t m)), Generic (a M)) => SimpleMethods a m t where
+class (Generic (a m), Generic (a (t m)), SimpleMethodsRep (Rep (a m)) (Rep (a (t m))) m t)
+    => SimpleMethods a (m :: * -> *) (t :: (* -> *) -> * -> *) where
     liftSimple :: a m -> a (t m)
-
-instance
-    ( Rep (a m) ~ D1 m1 (C1 m2 p)
-    , Rep (a M) ~ D1 m1 (C1 m2 pM)
-    , Rep (a (t m)) ~ D1 m1 (C1 m2 (LiftedProducts p pM m t))
-    , ProductOfSimpleMethods p pM m t
-    , Generic (a m), Generic (a (t m)), Generic (a M) )
+instance (Generic (a m), Generic (a (t m)), SimpleMethodsRep (Rep (a m)) (Rep (a (t m))) m t)
     => SimpleMethods a m t where
-    liftSimple a = case Gen.from a of
-        M1 (M1 p) -> Gen.to (M1 (M1 (liftProducts (Proxy @m) (Proxy @t) (Proxy @pM) p)))
-    {-# INLINE liftSimple #-}
-
-class ProductOfSimpleMethods p pM m t where
-    type LiftedProducts p pM m t :: * -> *
-    liftProducts :: Proxy m -> Proxy t -> Proxy pM -> p x -> LiftedProducts p pM m t x
+    liftSimple = Gen.to . liftSimpleRep @(Rep (a m)) @(Rep (a (t m))) @m @t . Gen.from
 
-instance SimpleMethod f fM m t => ProductOfSimpleMethods (S1 m1 (Rec0 f)) (S1 m1 (Rec0 fM)) m t where
-    type LiftedProducts (S1 m1 (Rec0 f)) (S1 m1 (Rec0 fM)) m t =
-        (S1 m1 (Rec0 (LiftedMethod f fM m t)))
-    liftProducts p1 p2 _ (M1 (K1 f)) = M1 (K1 (liftMethod p1 p2 (Proxy @fM) f))
-    {-# INLINE liftProducts #-}
-instance
-    (ProductOfSimpleMethods f1 f1M m t, ProductOfSimpleMethods f2 f2M m t)
-    => ProductOfSimpleMethods (f1 :*: f2) (f1M :*: f2M) m t where
-    type LiftedProducts (f1 :*: f2) (f1M :*: f2M) m t =
-        LiftedProducts f1 f1M m t :*: LiftedProducts f2 f2M m t
-    liftProducts p1 p2 _ (f1 :*: f2) =
-        liftProducts p1 p2 (Proxy @f1M) f1 :*: liftProducts p1 p2 (Proxy @f2M) f2
-    {-# INLINE liftProducts #-}
+class SimpleMethodsRep r r' (m :: * -> *) (t :: (* -> *) -> * -> *) where
+    liftSimpleRep :: r x -> r' x
+instance SimpleMethodsRep c c' m t => SimpleMethodsRep (M1 a b c) (M1 a b c') m t where
+    liftSimpleRep (M1 x) = M1 (liftSimpleRep @c @c' @m @t x)
+instance (SimpleMethodsRep a a' m t, SimpleMethodsRep b b' m t)
+    => SimpleMethodsRep (a :*: b) (a' :*: b') m t where
+    liftSimpleRep (a :*: b) = liftSimpleRep @a @a' @m @t a :*: liftSimpleRep @b @b' @m @t b
+instance (SimpleMethodsRep a a' m t, SimpleMethodsRep b b' m t)
+    => SimpleMethodsRep (a :+: b) (a' :+: b') m t where
+    liftSimpleRep (L1 a) = L1 (liftSimpleRep @a @a' @m @t a)
+    liftSimpleRep (R1 b) = R1 (liftSimpleRep @b @b' @m @t b)
+instance SimpleMethodsRep U1 U1 m t where
+    liftSimpleRep U1 = U1
+instance SimpleMethodsRep V1 V1 m t where
+    liftSimpleRep v = case v of {}
+instance SimpleMethod a a' m t
+    => SimpleMethodsRep (K1 x a) (K1 x a') m t where
+    liftSimpleRep (K1 m) = K1 (liftMethod @a @a' @m @t m)
 
-class (MonadTrans t, Monad m) => SimpleMethod f fM (m :: * -> *) (t :: (* -> *) -> * -> *) where
-    type LiftedMethod f fM m t
-    liftMethod :: Proxy m -> Proxy t -> Proxy fM -> f -> LiftedMethod f fM m t
-instance (MonadTrans t, Monad m, a ~ m x) => SimpleMethod a (M x) m t where
-    type LiftedMethod a (M x) m t = t m x
-    liftMethod _ _ _ = lift @t
-    {-# INLINE liftMethod #-}
-type family FuncRes f where
-    FuncRes (a -> b) = b
-instance (f ~ (a -> b), SimpleMethod b bM m t, IndependentOfM a m) => SimpleMethod f (a -> bM) m t where
-    type LiftedMethod f (a -> bM) m t = a -> LiftedMethod (FuncRes f) bM m t
-    liftMethod p1 p2 _ f a = liftMethod p1 p2 (Proxy @bM) (f a :: b)
-    {-# INLINE liftMethod #-}
+class SimpleMethod f ft (m :: * -> *) (t :: (* -> *) -> * -> *) where
+    liftMethod :: f -> ft
+instance SimpleMethod f ft m t => SimpleMethod (a -> f) (a -> ft) m t where
+    liftMethod f a = liftMethod @f @ft @m @t (f a)
 instance {-# OVERLAPPABLE #-}
-    ( TypeError ('Text "Effect methods must be monadic actions or functions resulting in monadic actions")
-    , Monad m, MonadTrans t )
-    => SimpleMethod a b m t
-
-class IndependentOfM (a :: k) (m :: * -> *) where
-instance
-    (IndependentOfM a m, IndependentOfM b m)
-    => IndependentOfM (a b) m
-instance
-    TypeError
-        ('Text "Parameters of methods can't depend on the monadic context ("
-        ':<>: 'ShowType m
-        ':<>: 'Text ")")
-    => IndependentOfM M m
+    ForceError (TypeError
+        ('Text "Parameters of methods can't depend on the monadic context."
+        ':$$: 'Text "The parameter `" ':<>: 'ShowType a ':<>: 'Text "` depends on `"
+        ':<>: 'ShowType m ':<>: 'Text "`"))
+    => SimpleMethod (a -> f) (a' -> ft) m t where
+    liftMethod = error "Unreachable"
+instance (MonadTrans t, Monad m) => SimpleMethod (m a) (t m a) m t where
+    liftMethod m = lift m
 instance {-# OVERLAPPABLE #-}
-    IndependentOfM (a :: k) m
+    ForceError (TypeError
+        ('Text "The result of all methods must be monadic."
+        ':$$: 'Text "One of the methods' result is of type `" ':<>: 'ShowType a
+        ':<>: 'Text "`. Maybe try `" ':<>: 'ShowType (m a) ':<>: 'Text "` instead."))
+    => SimpleMethod a b m t where
+    liftMethod = error "Unreachable"
 
 genericLiftThrough ::
     forall t e m. (MonadTrans t, Monad m, Monad (t m), SimpleMethods e m t)
@@ -83,54 +67,63 @@
 
 
 
-class MonadicMethods a m where
+
+
+class (Generic (a m), MonadicMethodsRep (Rep (a m)) m, Monad m) => MonadicMethods a m where
     mergeMonadicMethods :: m (a m) -> a m
-instance
-    ( Rep (a m) ~ D1 m1 (C1 m2 p)
-    , Rep (a M) ~ D1 m1 (C1 m2 pM)
-    , ProductOfMonadicMethods p pM a m
-    , Generic (a m), Generic (a M) )
-    => MonadicMethods a m where
-    mergeMonadicMethods a = Gen.to (M1 (M1 (mergeMonadicProducts (Proxy @p) (Proxy @pM) a f)))
-        where
-        f (Gen.from -> M1 (M1 p)) = p
-    {-# INLINE mergeMonadicMethods #-}
+instance (Generic (a m), MonadicMethodsRep (Rep (a m)) m, Monad m) => MonadicMethods a m where
+    mergeMonadicMethods m = Gen.to (mergeMonadicMethodsRep @(Rep (a m)) @m (fmap Gen.from m))
 
-class ProductOfMonadicMethods p pM a m where
-    mergeMonadicProducts :: Proxy p -> Proxy pM -> m (a m) -> (a m -> p x) -> p x
-instance MonadicMethod a f fM m => ProductOfMonadicMethods (S1 m1 (Rec0 f)) (S1 m1 (Rec0 fM)) a m where
-    mergeMonadicProducts _ _ ma f = M1 (K1 (mergeMethod (Proxy @fM) (g . f) ma))
+class MonadicMethodsRep r m where
+    mergeMonadicMethodsRep :: m (r x) -> r x
+instance (MonadicMethodsRep c m, Functor m) => MonadicMethodsRep (M1 a b c) m where
+    mergeMonadicMethodsRep m = M1 (mergeMonadicMethodsRep @c @m (fmap unM1 m))
+instance (MonadicMethodsRep a m, MonadicMethodsRep b m, Functor m)
+    => MonadicMethodsRep (a :*: b) m where
+    mergeMonadicMethodsRep m =
+        mergeMonadicMethodsRep @a @m (fmap l m)
+        :*: mergeMonadicMethodsRep @b @m (fmap r m)
         where
-        g (M1 (K1 x)) = x
-    {-# INLINE mergeMonadicProducts #-}
+        l (x :*: _) = x
+        r (_ :*: x) = x
 instance
-    (ProductOfMonadicMethods f1 f1M a m, ProductOfMonadicMethods f2 f2M a m)
-    => ProductOfMonadicMethods (f1 :*: f2) (f1M :*: f2M) a m where
-    mergeMonadicProducts _ _ ma f =
-        mergeMonadicProducts (Proxy @f1) (Proxy @f1M) ma (g1 . f)
-        :*: mergeMonadicProducts (Proxy @f2) (Proxy @f2M) ma (g2 . f)
-        where
-        g1 (x :*: _) = x
-        g2 (_ :*: x) = x
-    {-# INLINE mergeMonadicProducts #-}
+    ForceError (TypeError
+        ('Text "Can't automatically derive Effect instance for an effect with multiple constructors."))
+    => MonadicMethodsRep (a :+: b) m where
+    mergeMonadicMethodsRep = error "Unreachable"
+instance MonadicMethodsRep U1 m where
+    mergeMonadicMethodsRep _ = U1
+instance
+    ForceError (TypeError
+        ('Text "Can't automatically derive Effect instance for an effect with no constructors."))
+    => MonadicMethodsRep V1 m where
+    mergeMonadicMethodsRep = error "Unreachable"
+instance (MonadicMethod a m, Functor m)
+    => MonadicMethodsRep (K1 x a) m where
+    mergeMonadicMethodsRep m = K1 (mergeMonadicMethod @a @m (fmap unK1 m))
 
-class Monad m => MonadicMethod a f fM m where
-    mergeMethod :: Proxy fM -> (a m -> f) -> m (a m) -> f
-instance (b ~ m x, Monad m) => MonadicMethod a b (M x) m where
-    mergeMethod _ f ma = do
-        a <- ma
-        f a
-    {-# INLINE mergeMethod #-}
-instance (f ~ (b -> c), Monad m, MonadicMethod a c cM m) => MonadicMethod a f (bM -> cM) m where
-    mergeMethod _ f ma b = mergeMethod (Proxy @cM) (g . f) ma
-        where
-        g = ($ b)
-    {-# INLINE mergeMethod #-}
+class MonadicMethod a m where
+    mergeMonadicMethod :: m a -> a
+instance {-# INCOHERENT #-}
+    (MonadicMethod b m, Functor m)
+    => MonadicMethod (a -> b) m where
+    mergeMonadicMethod m a = mergeMonadicMethod (fmap ($ a) m)
+instance Monad m => MonadicMethod (m a) m where
+    mergeMonadicMethod = join
 instance {-# OVERLAPPABLE #-}
-    ( TypeError ('Text "Effect methods must be monadic actions or functions resulting in monadic actions")
-    , Monad m )
-    => MonadicMethod a f fM m
+    ForceError (TypeError
+        ('Text "The result of all methods must be monadic."
+        ':$$: 'Text "One of the methods' result is of type `" ':<>: 'ShowType a
+        ':<>: 'Text "`. Maybe try `" ':<>: 'ShowType (m a) ':<>: 'Text "` instead."))
+    => MonadicMethod a m where
+    mergeMonadicMethod = error "Unreachable"
 
 genericMergeContext :: MonadicMethods a m => m (a m) -> a m
 genericMergeContext = mergeMonadicMethods
 {-# INLINE genericMergeContext #-}
+
+
+
+
+
+class ForceError (x :: *)
diff --git a/src/Control/Effects/Newtype.hs b/src/Control/Effects/Newtype.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Effects/Newtype.hs
@@ -0,0 +1,75 @@
+{-# LANGUAGE TypeApplications, ScopedTypeVariables, AllowAmbiguousTypes #-}
+{-# LANGUAGE FlexibleContexts, KindSignatures, PolyKinds #-}
+{-# LANGUAGE TypeFamilies, FlexibleInstances, MultiParamTypeClasses #-}
+{-# LANGUAGE UndecidableInstances, DataKinds, NoMonomorphismRestriction #-}
+-- | Sometimes it's useful to give a new name to an already existing effect. This module provides
+--   the tools to make that easy to do.
+module Control.Effects.Newtype where
+
+import Import (ask)
+import Control.Effects
+import Data.Coerce
+import Control.Effects.State
+
+-- | If we have a computation using some effect @original@, we can convert it into a computation
+--   that uses the effect @newtyped@ instead. Provided, of course, that @newtyped@ is really a
+--   newtype over the @original@ effect.
+--
+-- @
+-- f :: 'MonadEffect' ('State' Int) m => m ()
+-- f = getState >>= \i -> setState (i + 1)
+--
+-- newtype MyState m = MyState ('State' Int m)
+--
+-- -- inferred: g :: 'MonadEffect' MyState m => m ()
+-- g = 'effectAsNewtype' \@MyState \@('State' Int) f
+-- @
+effectAsNewtype :: forall newtyped original m a.
+    (MonadEffect newtyped m, Coercible (newtyped m) (original m))
+    => RuntimeImplemented original m a -> m a
+effectAsNewtype = implement (coerce (effect @newtyped :: newtyped m))
+
+-- | A useful newtype for any effect. Just provide a unique tag, like a type level string.
+newtype EffTag (tag :: k) e (m :: * -> *) = EffTag (e m)
+instance Effect e => Effect (EffTag tag e) where
+    type CanLift (EffTag tag e) t = CanLift e t
+    liftThrough (EffTag e) = EffTag (liftThrough e)
+    mergeContext m = EffTag (mergeContext (fmap coerce m))
+
+instance {-# INCOHERENT #-}
+    ( e ~ e', Effect e, Monad m
+    , CanLift e (RuntimeImplemented (EffTag tag e)) )
+    => MonadEffect (EffTag tag e) (RuntimeImplemented (EffTag tag e') m) where
+    effect = mergeContext $ RuntimeImplemented (liftThrough <$> ask)
+
+-- | Rename an effect without explicitly declaring a new newtype. Just provide a tag.
+--   This is useful if you have two functions using the same effect that you want to combine but
+--   you don't want their effects to interact. For example, maybe they both work with @Int@ states
+--   but you don't want them to modify each other's number.
+tagEffect :: forall tag original m a.
+    MonadEffect (EffTag tag original) m
+    => RuntimeImplemented original m a -> m a
+tagEffect = effectAsNewtype @(EffTag tag original)
+
+-- | Once you tag your effect, it's /slightly/ inconvenient that you have to wrap your implementation
+--   when you want to handle it. This function doees the wrapping for you.
+--
+-- @
+-- f :: 'MonadEffect' ('State' Int) m => m ()
+-- f = 'getState' >>= \\s -> 'setState' (s * 2)
+--
+-- g :: 'MonadEffect' ('State' Int) m => m ()
+-- g = 'getState' >>= \\s -> 'setState' (s * 3)
+--
+-- combine :: Monad m => m Int
+-- combine =
+--     'implementStateViaStateT' 5 $ 'implementTagged' \@"s2" ('StateMethods' 'getState' 'setState')
+--     $ 'implementStateViaStateT' 0 $ 'implementTagged' \@"s1" ('StateMethods' 'getState' 'setState')
+--     $ do
+--     r1 \<- 'tagEffect' \@"s1" \@('State' Int) (f >> 'getState')
+--     r2 \<- 'tagEffect' \@"s2" \@('State' Int) (g >> 'getState')
+--     return (r1 + r2) -- results in 15
+-- @
+implementTagged :: forall tag original m a.
+    original m -> RuntimeImplemented (EffTag tag original) m a -> m a
+implementTagged = implement . coerce
diff --git a/src/Control/Effects/Parallel.hs b/src/Control/Effects/Parallel.hs
deleted file mode 100644
--- a/src/Control/Effects/Parallel.hs
+++ /dev/null
@@ -1,48 +0,0 @@
-{-# LANGUAGE ScopedTypeVariables, FlexibleContexts #-}
-module Control.Effects.Parallel where
-
-import Import hiding (State)
-
-import GHC.MVar
-import GHC.IO.Unsafe
-import Data.Array.IO
-import Control.Concurrent
-
-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, MonadEffect (State 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
diff --git a/src/Control/Effects/State.hs b/src/Control/Effects/State.hs
--- a/src/Control/Effects/State.hs
+++ b/src/Control/Effects/State.hs
@@ -4,15 +4,16 @@
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE TypeApplications #-}
 {-# LANGUAGE NoMonomorphismRestriction #-}
+{-# LANGUAGE FlexibleInstances #-}
 -- | The 'MonadState' you know and love with some differences. First, there's no functional
 --   dependency limiting your stack to a single state type. This means less type inference so
---   it might not be enough to just write 'getState'. Write 'getState @MyStateType' instead using
---   TypeApplications.
+--   it might not be enough to just write 'getState'. Write @'getState' \@MyStateType@ instead using
+--   @TypeApplications@.
 --
 --   Second, the functions have less generic names and are called 'getState' and 'setState'.
 --
 --   Third, since it's a part of this effect framework, you get an 'implement' function with
---   which you can provide a different state implementation _at runtime_.
+--   which you can provide a different state implementation /at runtime/.
 module Control.Effects.State (module Control.Effects.State, module Control.Effects) where
 
 import Import hiding (State)
@@ -26,6 +27,7 @@
     , _setState :: s -> m () }
     deriving (Generic)
 instance Effect (State s) where
+    type ExtraConstraint (State s) m = UniqueEffect State m s
 
 -- | Get current value of the state with the type 's'.
 -- You can use type applications to tell the type checker which type of state you want.
@@ -46,6 +48,8 @@
     let s' = f s
     s' `seq` setState s'
 
+instance UniqueEffect State (StateT s m) s
+instance UniqueEffect State (RuntimeImplemented (State s) m) s
 instance Monad m => MonadEffect (State s) (StateT s m) where
     effect = StateMethods get put
 
diff --git a/src/Control/Effects/Yield.hs b/src/Control/Effects/Yield.hs
--- a/src/Control/Effects/Yield.hs
+++ b/src/Control/Effects/Yield.hs
@@ -6,6 +6,8 @@
 {-# LANGUAGE NoMonomorphismRestriction #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 {-| The @'Yield' a@ effect lets a computation produce values of type @a@ during it's execution. -}
 module Control.Effects.Yield where
 
@@ -21,8 +23,11 @@
 newtype Yield a m = YieldMethods
     { _yield :: a -> m () }
     deriving (Generic)
-instance Effect (Yield a)
+instance Effect (Yield a) where
+    type ExtraConstraint (Yield a) m = UniqueEffect Yield m a
 
+instance UniqueEffect Yield (RuntimeImplemented (Yield a) m) a
+
 -- | Output a value of type @a@. The semantics are determined by the implementation, but usually this
 --   will block until the next value is requested by the consumer.
 yield :: forall a m. MonadEffect (Yield a) m => a -> m ()
@@ -61,7 +66,7 @@
 --   [Note]
 --      'yield' will block in this implementation.
 implementYieldViaMVar ::
-    forall a m b. (MonadIO m, MonadEffect Async m)
+    forall a thread m b. (MonadIO m, MonadEffect (Async thread) m)
     => RuntimeImplemented (Yield a) m b -> m (m (Maybe a))
 implementYieldViaMVar m = do
     mv <- liftIO newEmptyMVar
@@ -91,7 +96,7 @@
 --  [Note]
 --      'yield' will /not/ block in this implementation.
 implementYieldViaChan ::
-    forall a m b. (MonadIO m, MonadEffect Async m)
+    forall a thread m b. (MonadIO m, MonadEffect (Async thread) m)
     => RuntimeImplemented (Yield a) m b -> m (m (Maybe a))
 implementYieldViaChan m = do
     ch <- liftIO newChan
diff --git a/src/Tutorial/T2_Details.hs b/src/Tutorial/T2_Details.hs
--- a/src/Tutorial/T2_Details.hs
+++ b/src/Tutorial/T2_Details.hs
@@ -107,6 +107,10 @@
 class 'Effect' (e :: (* -> *) -> *) where
     type 'CanLift' e (t :: (* -> *) -> * -> *) :: 'Constraint'
     type 'CanLift' e t = 'MonadTrans' t
+
+    type ExtraConstraint e (m :: * -> *) :: Constraint
+    type ExtraConstraint e m = ()
+
     'liftThrough' ::
         ('CanLift' e t, 'Monad' m, 'Monad' (t m))
         => e m -> e (t m)
@@ -126,6 +130,14 @@
     Then there's the 'CanLift' associated type. It specifies the constraint that a transformer needs to satisfy
     to be able to lift the effect through it. Usually, 'MonadTrans' is all you need, so that's the
     default instantiation. Some more complicated effects have tighter demands.
+
+    The `ExtraConstraint` associated type lets you put additional requirements on monads that support
+    your effect. The motivation for this extra constraint is that it allows to have parameters on
+    your effect (like the @s@ parameter in @'State' s@) but still allow only one instantiation of
+    it. For example, you can't have a function with multiple different states. This restriction
+    makes type inferrence much better in some cases and doesn't seem to get in the way too much in
+    practice. If you do end up needing multiple states, check out the "Control.Effects.Newtype"
+    module.
 
     The 'liftThrough' function gets an implementation of the effect @e@ in the monad @m@ and is
     required to provide an implementation in the monad @t m@. Here's how it might look for the
diff --git a/src/Tutorial/T3_CustomEffects.hs b/src/Tutorial/T3_CustomEffects.hs
--- a/src/Tutorial/T3_CustomEffects.hs
+++ b/src/Tutorial/T3_CustomEffects.hs
@@ -124,6 +124,8 @@
 main :: IO ()
 main = do
     'implement' (FilesMethods 'B.readFile' 'B.writeFile') myFunc
+    -- *NOTE* The readFile and writeFile functions used here are *not* the ones we defined above
+    -- They're imported from the Data.ByteString module
 @
 
     Here we implemented our effect using the 'B.readFile' and 'B.writeFile' functions from the
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -7,7 +7,6 @@
 import Control.Monad
 import Control.Effects.Signal
 import Control.Effects.State
-import Control.Effects.Parallel
 import Control.Effects.Early
 import Control.Effects.Async
 import Control.Effects.List
@@ -29,7 +28,7 @@
     void $ discardAllExceptions ex1
     void $ showAllExceptions ex2
     handleException (\(_ :: Bool) -> return ()) ex2
-    handleSignal (\(_ :: Bool) -> Resume 5) ex1
+    handleSignal (\(_ :: Bool) -> return $ Resume 5) ex1
 
 -- Nested Early
 testEarly1 :: Monad m => m Bool
@@ -76,12 +75,12 @@
     putStrLn "Sequential test done"
     putStrLn "Starting parallel test"
     implementStateViaStateT (0 :: Int) $ do
-        res <- parallelWithSequence (replicate 8 task)
+        res <- parallelMapM id (replicate 8 task)
         mapM_ (liftIO . print) res
     putStrLn "Parallel test done"
 
 parallelTest ::
-    (MonadEffects '[Async, NonDeterminism] m, MonadIO m) => m (AsyncThread m (Int, Char))
+    (MonadEffects '[Async thread, NonDeterminism] m, MonadIO m) => m (thread m (Int, Char))
 parallelTest = do
     n <- choose [1,2,3,4]
     async $ do
@@ -99,7 +98,7 @@
             )
 
 yieldTest ::
-    (MonadEffects '[Yield Int, Async] m, MonadIO m) => m ()
+    (MonadEffects '[Yield Int, Async thread] m, MonadIO m) => m ()
 yieldTest = do
     yield @Int 5
     t <- async $ do
