diff --git a/CHANGES.md b/CHANGES.md
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,15 @@
 # Change log
 
+## 0.6
+
+* Start supporting GHC 9.4. See #66.
+* Add `ComposeTraversable`. See #65.
+* Make the `Applicative` instance of `ComposeEither` more interesting by relying
+  on the `Selective f` constraint. See #64.
+* Make the `Lift` instance lazier. See #63.
+* Stop supporting GHC <= 8.6. See #62.
+* Add `Control.Selective.Trans.Except` transformer. See #39.
+
 ## 0.5
 
 * Allow `transformers-0.6`, see #47.
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2018-2021 Andrey Mokhov
+Copyright (c) 2018-2023 Andrey Mokhov
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Selective applicative functors
 
-[![Hackage version](https://img.shields.io/hackage/v/selective.svg?label=Hackage)](https://hackage.haskell.org/package/selective) [![Build status](https://img.shields.io/github/workflow/status/snowleopard/selective/ci.svg)](https://github.com/snowleopard/selective/actions)
+[![Hackage version](https://img.shields.io/hackage/v/selective.svg?label=Hackage)](https://hackage.haskell.org/package/selective) [![Build status](https://img.shields.io/github/workflow/status/snowleopard/selective/ci/master.svg)](https://github.com/snowleopard/selective/actions)
 
 This is a library for *selective applicative functors*, or just *selective functors*
 for short, an abstraction between applicative functors and monads, introduced in
diff --git a/examples/Parser.hs b/examples/Parser.hs
--- a/examples/Parser.hs
+++ b/examples/Parser.hs
@@ -40,17 +40,17 @@
     (c:cs) -> [(c,cs)]
 
 sat :: (Char -> Bool) -> Parser Char
-sat p = do { c <- item; if p c then return c else zero }
+sat p = do { c <- item; if p c then pure c else zero }
 
 char :: Char -> Parser Char
 char c = sat (==c)
 
 string :: String -> Parser String
-string []     = return ""
+string []     = pure ""
 string (c:cs) = do
     _ <- char c
     _ <- string cs
-    return (c:cs)
+    pure (c:cs)
 
 bin :: Parser Int
 bin = undefined
diff --git a/examples/Query.hs b/examples/Query.hs
--- a/examples/Query.hs
+++ b/examples/Query.hs
@@ -51,11 +51,11 @@
 getPure (Apply f x) = do
     pf <- getPure f
     px <- getPure x
-    return (pf px)
+    pure (pf px)
 getPure (Select x y) = do
     px <- getPure x
     py <- getPure y
-    return (either py id px)
+    pure (either py id px)
 
 getEffects :: Query a -> ([Prompt], [FilePath])
 getEffects (Terminal p) = ([p], [] )
diff --git a/examples/Teletype.hs b/examples/Teletype.hs
--- a/examples/Teletype.hs
+++ b/examples/Teletype.hs
@@ -3,6 +3,7 @@
 
 import Prelude hiding (getLine, putStrLn)
 import qualified Prelude as IO
+import qualified Control.Monad as IO
 import Control.Selective
 import Control.Selective.Free
 
@@ -69,7 +70,7 @@
 -- | Monadic ping-pong, which has the desired behaviour, but cannot be
 -- statically analysed.
 pingPongM :: IO ()
-pingPongM = IO.getLine >>= \s -> if s == "ping" then IO.putStrLn "pong" else pure ()
+pingPongM = IO.getLine >>= \s -> IO.when (s == "ping") (IO.putStrLn "pong")
 
 -- | Applicative ping-pong, which always executes both effect, but can be
 -- statically analysed.
diff --git a/examples/Teletype/Rigid.hs b/examples/Teletype/Rigid.hs
--- a/examples/Teletype/Rigid.hs
+++ b/examples/Teletype/Rigid.hs
@@ -3,6 +3,7 @@
 
 import Prelude hiding (getLine, putStrLn)
 import qualified Prelude as IO
+import qualified Control.Monad as IO
 import Control.Selective
 import Control.Selective.Rigid.Free
 
@@ -62,7 +63,7 @@
 -- | Monadic ping-pong, which has the desired behaviour, but cannot be
 -- statically analysed.
 pingPongM :: IO ()
-pingPongM = IO.getLine >>= \s -> if s == "ping" then IO.putStrLn "pong" else pure ()
+pingPongM = IO.getLine >>= \s -> IO.when (s == "ping") (IO.putStrLn "pong")
 
 -- | Applicative ping-pong, which always executes both effect, but can be
 -- statically analysed.
diff --git a/selective.cabal b/selective.cabal
--- a/selective.cabal
+++ b/selective.cabal
@@ -1,17 +1,17 @@
 name:          selective
-version:       0.5
+version:       0.6
 synopsis:      Selective applicative functors
 license:       MIT
 license-file:  LICENSE
 author:        Andrey Mokhov <andrey.mokhov@gmail.com>, github: @snowleopard
 maintainer:    Andrey Mokhov <andrey.mokhov@gmail.com>, github: @snowleopard
-copyright:     Andrey Mokhov, 2018-2021
+copyright:     Andrey Mokhov, 2018-2023
 homepage:      https://github.com/snowleopard/selective
 bug-reports:   https://github.com/snowleopard/selective/issues
 category:      Control
 build-type:    Simple
 cabal-version: 1.18
-tested-with:   GHC==9.0, GHC==8.10, GHC==8.8, GHC==8.6, GHC==8.4, GHC==8.2, GHC==8.0
+tested-with:   GHC==9.4.4, GHC==9.2.6, GHC==9.0.2, GHC==8.10.7, GHC==8.8.4, GHC==8.6.5
 description:   Selective applicative functors: declare your effects statically,
                select which to execute dynamically.
                .
@@ -34,7 +34,8 @@
                         Control.Selective.Free,
                         Control.Selective.Multi,
                         Control.Selective.Rigid.Free,
-                        Control.Selective.Rigid.Freer
+                        Control.Selective.Rigid.Freer,
+                        Control.Selective.Trans.Except
     build-depends:      base         >= 4.9     && < 5,
                         containers   >= 0.5.5.1 && < 0.7,
                         transformers >= 0.4.2.0 && < 0.7
@@ -55,7 +56,7 @@
     if impl(ghc >= 9.2)
         ghc-options:    -Wno-operator-whitespace-ext-conflict
 
-test-suite test
+test-suite main
     hs-source-dirs:     test, examples
     other-modules:      Build,
                         Laws,
diff --git a/src/Control/Selective.hs b/src/Control/Selective.hs
--- a/src/Control/Selective.hs
+++ b/src/Control/Selective.hs
@@ -1,10 +1,10 @@
 {-# LANGUAGE CPP, LambdaCase, TupleSections, DeriveTraversable #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving, DerivingVia #-}
 {-# OPTIONS_GHC -fno-warn-unused-imports #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module     : Control.Selective
--- Copyright  : (c) Andrey Mokhov 2018-2019
+-- Copyright  : (c) Andrey Mokhov 2018-2023
 -- License    : MIT (see the file LICENSE)
 -- Maintainer : andrey.mokhov@gmail.com
 -- Stability  : experimental
@@ -27,7 +27,7 @@
     SelectA (..), SelectM (..), Over (..), Under (..), Validation (..),
 
     -- * Miscellaneous
-    swapEither, ComposeEither (..)
+    swapEither, ComposeEither (..), ComposeTraversable (..)
     ) where
 
 import Control.Applicative
@@ -35,7 +35,6 @@
 import Control.Arrow
 import Control.Monad.ST
 import Control.Monad.Trans.Cont
-import Control.Monad.Trans.Except
 import Control.Monad.Trans.Identity
 import Control.Monad.Trans.Maybe
 import Control.Monad.Trans.Reader
@@ -197,10 +196,10 @@
 selectA :: Applicative f => f (Either a b) -> f (a -> b) -> f b
 selectA x y = (\e f -> either f id e) <$> x <*> y
 
--- | If a functor is both 'Applicative' and 'Traversable', we can implement
--- 'select' in another interesting way: the effects associated with the second
--- argument can be skipped as long as the first argument contains only 'Right's.
-selectT :: (Applicative f, Traversable f) => f (Either a b) -> f (a -> b) -> f b
+-- | For traversable functors, we can implement 'select' in another interesting
+-- way: the effects associated with the second argument can be skipped as long
+-- as the first argument contains only 'Right' values.
+selectT :: Traversable f => f (Either a b) -> f (a -> b) -> f b
 selectT x y = case sequenceA x of
     Left  a  -> ($a) <$> y
     Right fb -> fb
@@ -275,7 +274,7 @@
 matchM :: Monad m => Cases a -> m a -> (a -> m b) -> m (Either a b)
 matchM (Cases _ p) mx f = do
     x <- mx
-    if p x then Right <$> f x else return (Left x)
+    if p x then Right <$> f x else pure (Left x)
 
 -- TODO: Add a type-safe version based on @KnownNat@.
 -- | A restricted version of monadic bind. Fails with an error if the 'Bounded'
@@ -302,8 +301,15 @@
 
 -- | Return the first @Right@ value. If both are @Left@'s, accumulate errors.
 orElse :: (Selective f, Semigroup e) => f (Either e a) -> f (Either e a) -> f (Either e a)
-orElse x y = branch x (flip appendLeft <$> y) (pure Right)
+orElse x y = select (prepare <$> x) (combine <$> y)
+  where
+    prepare :: Either e a -> Either e (Either e a)
+    prepare = fmap Right
 
+    combine :: Semigroup e => Either e a -> e -> Either e a
+    combine (Left ey) ex = Left (ex <> ey)
+    combine (Right a) _  = Right a
+
 -- | Accumulate the @Right@ values, or return the first @Left@.
 andAlso :: (Selective f, Semigroup a) => f (Either e a) -> f (Either e a) -> f (Either e a)
 andAlso x y = swapEither <$> orElse (swapEither <$> x) (swapEither <$> y)
@@ -312,11 +318,6 @@
 swapEither :: Either a b -> Either b a
 swapEither = either Right Left
 
--- | Append two semigroup values or return the @Right@ one.
-appendLeft :: Semigroup a => a -> Either a b -> Either a b
-appendLeft a1 (Left a2) = Left (a1 <> a2)
-appendLeft _  (Right b) = Right b
-
 -- | Keep checking an effectful condition while it holds.
 whileS :: Selective f => f Bool -> f ()
 whileS act = whenS act (whileS act)
@@ -348,11 +349,7 @@
 allS p = foldr ((<&&>) . p) (pure True)
 
 -- | Generalised folding with the short-circuiting behaviour.
-foldS :: (Selective f, Foldable t, Monoid a
-#if !MIN_VERSION_base(4,11,0)
-  , Semigroup a
-#endif
-    ) => t (f (Either e a)) -> f (Either e a)
+foldS :: (Selective f, Foldable t, Monoid a) => t (f (Either e a)) -> f (Either e a)
 foldS = foldr andAlso (pure (Right mempty))
 
 -- Instances
@@ -374,8 +371,8 @@
 
 -- Note: Validation e a ~ Lift (Under e) a
 instance Selective f => Selective (Lift f) where
+    select (Pure (Right x)) _         = Pure x -- Lazy in the second argument
     select              x   (Pure  y) = either y id <$> x
-    select (Pure (Right x)) _         = Pure x
     select (Pure (Left  x)) (Other y) = Other $ ($x) <$> y
     select (Other       x ) (Other y) = Other $   x  <*? y
 
@@ -397,10 +394,7 @@
 -- | Static analysis of selective functors with over-approximation.
 newtype Over m a = Over { getOver :: m }
     deriving (Eq, Functor, Ord, Show)
-
-instance Monoid m => Applicative (Over m) where
-    pure _            = Over mempty
-    Over x <*> Over y = Over (mappend x y)
+    deriving Applicative via (Const m)
 
 -- select = selectA
 instance Monoid m => Selective (Over m) where
@@ -409,10 +403,7 @@
 -- | Static analysis of selective functors with under-approximation.
 newtype Under m a = Under { getUnder :: m }
     deriving (Eq, Functor, Ord, Show, Foldable, Traversable)
-
-instance Monoid m => Applicative (Under m) where
-    pure _              = Under mempty
-    Under x <*> Under y = Under (mappend x y)
+    deriving Applicative via (Const m)
 
 -- select = selectT
 instance Monoid m => Selective (Under m) where
@@ -510,7 +501,6 @@
 instance             Selective STM        where select = selectM
 
 instance                        Selective (ContT      r m) where select = selectM
-instance            Monad m  => Selective (ExceptT    e m) where select = selectM
 instance            Monad m  => Selective (MaybeT       m) where select = selectM
 instance (Monoid w, Monad m) => Selective (RWST   r w s m) where select = selectM
 instance (Monoid w, Monad m) => Selective (S.RWST r w s m) where select = selectM
@@ -529,20 +519,42 @@
 toArrow :: Arrow a => ArrowMonad a (i -> o) -> a i o
 toArrow (ArrowMonad f) = arr ((),) >>> first f >>> arr (uncurry ($))
 
----------------------------------- Alternative ---------------------------------
--- | Composition of a functor @f@ with the 'Either' monad.
+------------------------------ ComposeTraversable ------------------------------
+-- | Composition of a selective functor @f@ and an applicative traversable
+-- functor @g@.
+newtype ComposeTraversable f g a = ComposeTraversable (f (g a))
+    deriving (Functor, Applicative) via Compose f g
+
+instance (Selective f, Applicative g, Traversable g) => Selective (ComposeTraversable f g) where
+    select (ComposeTraversable x) (ComposeTraversable f) = ComposeTraversable $
+        select (prepare <$> x) (combine <$> f)
+      where
+        prepare :: Traversable g => g (Either a b) -> Either a (g b)
+        prepare = sequenceA
+
+        combine :: Traversable g => g (a -> b) -> a -> g b
+        combine = sequenceA
+
+--------------------------------- ComposeEither --------------------------------
+-- | Composition of a selective functor @f@ with the 'Either' monad.
 newtype ComposeEither f e a = ComposeEither (f (Either e a))
-    deriving Functor
+    deriving Functor via Compose f (Either e)
+    deriving Selective via ComposeTraversable f (Either e)
 
-instance Applicative f => Applicative (ComposeEither f e) where
-    pure a                              = ComposeEither (pure $ Right a)
-    ComposeEither x <*> ComposeEither y = ComposeEither ((<*>) <$> x <*> y)
+instance Selective f => Applicative (ComposeEither f e) where
+    pure = ComposeEither . pure . Right
 
-instance (Selective f, Monoid e
-#if !MIN_VERSION_base(4,11,0)
-  , Semigroup e
-#endif
-    ) => Alternative (ComposeEither f e) where
+    ComposeEither f <*> ComposeEither a = ComposeEither $
+        select (prepare <$> f) (combine <$> a)
+      where
+        prepare :: Either e (a -> b) -> Either (a -> b) (Either e b)
+        prepare = either (Right . Left) Left
+
+        combine :: Either e a -> (a -> b) -> Either e b
+        combine = flip fmap
+
+---------------------------------- Alternative ---------------------------------
+instance (Selective f, Monoid e) => Alternative (ComposeEither f e) where
     empty                               = ComposeEither (pure $ Left mempty)
     ComposeEither x <|> ComposeEither y = ComposeEither (x `orElse` y)
 
@@ -559,7 +571,7 @@
 1) A generic 'failIfLeft' if not possible, although many actual instances should
    be able to implement it.
 
-2) More importantly, this requires duplication of work: if we failed becauase we
+2) More importantly, this requires duplication of work: if we failed because we
    happened to parse a 'Left' value in the first parser, then we need to rerun
    it, obtain a 'Left' once again, and then execute the second parser. Again, a
    specific instance may be able to cache the result and reuse it without
diff --git a/src/Control/Selective/Free.hs b/src/Control/Selective/Free.hs
--- a/src/Control/Selective/Free.hs
+++ b/src/Control/Selective/Free.hs
@@ -2,7 +2,7 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module     : Control.Selective.Free
--- Copyright  : (c) Andrey Mokhov 2018-2019
+-- Copyright  : (c) Andrey Mokhov 2018-2023
 -- License    : MIT (see the file LICENSE)
 -- Maintainer : andrey.mokhov@gmail.com
 -- Stability  : experimental
diff --git a/src/Control/Selective/Multi.hs b/src/Control/Selective/Multi.hs
--- a/src/Control/Selective/Multi.hs
+++ b/src/Control/Selective/Multi.hs
@@ -3,7 +3,7 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module     : Control.Selective.Multi
--- Copyright  : (c) Andrey Mokhov 2018-2020
+-- Copyright  : (c) Andrey Mokhov 2018-2023
 -- License    : MIT (see the file LICENSE)
 -- Maintainer : andrey.mokhov@gmail.com
 -- Stability  : experimental
diff --git a/src/Control/Selective/Rigid/Free.hs b/src/Control/Selective/Rigid/Free.hs
--- a/src/Control/Selective/Rigid/Free.hs
+++ b/src/Control/Selective/Rigid/Free.hs
@@ -2,7 +2,7 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module     : Control.Selective.Rigid.Free
--- Copyright  : (c) Andrey Mokhov 2018-2019
+-- Copyright  : (c) Andrey Mokhov 2018-2023
 -- License    : MIT (see the file LICENSE)
 -- Maintainer : andrey.mokhov@gmail.com
 -- Stability  : experimental
@@ -30,7 +30,7 @@
     getPure, getEffects, getNecessaryEffect, runSelect, foldSelect
     ) where
 
-import Control.Monad.Trans.Except
+import Control.Selective.Trans.Except
 import Control.Selective
 import Data.Bifunctor
 import Data.Functor
diff --git a/src/Control/Selective/Rigid/Freer.hs b/src/Control/Selective/Rigid/Freer.hs
--- a/src/Control/Selective/Rigid/Freer.hs
+++ b/src/Control/Selective/Rigid/Freer.hs
@@ -2,7 +2,7 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module     : Control.Selective.Rigid.Freer
--- Copyright  : (c) Andrey Mokhov 2018-2019
+-- Copyright  : (c) Andrey Mokhov 2018-2023
 -- License    : MIT (see the file LICENSE)
 -- Maintainer : andrey.mokhov@gmail.com
 -- Stability  : experimental
@@ -26,7 +26,7 @@
     getPure, getEffects, getNecessaryEffect, runSelect, foldSelect
     ) where
 
-import Control.Monad.Trans.Except
+import Control.Selective.Trans.Except
 import Control.Selective
 import Data.Bifunctor
 import Data.Function
diff --git a/src/Control/Selective/Trans/Except.hs b/src/Control/Selective/Trans/Except.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Selective/Trans/Except.hs
@@ -0,0 +1,95 @@
+{-# LANGUAGE CPP, GeneralizedNewtypeDeriving, DeriveTraversable, DerivingVia #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module     : Control.Selective.Trans.Except
+-- Copyright  : (c) Andrey Mokhov 2018-2023
+-- License    : MIT (see the file LICENSE)
+-- Maintainer : andrey.mokhov@gmail.com
+-- Stability  : experimental
+--
+-- This is a library for /selective applicative functors/, or just
+-- /selective functors/ for short, an abstraction between applicative functors
+-- and monads, introduced in this paper:
+-- https://www.staff.ncl.ac.uk/andrey.mokhov/selective-functors.pdf.
+--
+-- This module defines a newtype around 'ExceptT' from @transformers@ with less
+-- restrictive 'Applicative', 'Selective', and 'Alternative' implementations.
+-- It supplies an @instance 'Selective' f => 'Selective' ('ExceptT' e f)@, which
+-- makes 'ExceptT' a bona-fide 'Selective' transformer.
+--
+-- The API follows the API from the @transformers@ package, so it can be used as
+-- a drop-in replacement. The documentation can be found in the
+-- [@transformers@](https://hackage.haskell.org/package/transformers/docs/Control-Monad-Trans-Except.html) package.
+-----------------------------------------------------------------------------
+module Control.Selective.Trans.Except where
+
+import Control.Applicative (Alternative)
+import Control.Monad (MonadPlus)
+import Control.Monad.Fix (MonadFix)
+import Control.Monad.IO.Class (MonadIO)
+import Control.Monad.Zip (MonadZip)
+import Data.Functor.Classes
+import Data.Functor.Contravariant (Contravariant)
+import Data.Functor.Identity
+#if MIN_VERSION_base(4,13,0)
+-- MonadFail is imported already
+#else
+import Control.Monad.Fail
+#endif
+
+import qualified Control.Monad.Trans.Except as T
+import Control.Monad.Trans.Class
+
+import Control.Selective
+import Control.Monad.Signatures
+
+-- | A newtype wrapper around 'T.ExceptT' from @transformers@ that provides less
+-- restrictive 'Applicative', 'Selective' and 'Alternative' instances.
+newtype ExceptT e f a = ExceptT { unwrap :: T.ExceptT e f a }
+  deriving
+    ( Functor, Foldable, Traversable, Monad, Contravariant, Eq, Ord, Read, Show
+    , MonadTrans, MonadFix, MonadFail, MonadZip, MonadIO, MonadPlus, Eq1, Ord1
+    , Read1, Show1 )
+  deriving (Applicative, Selective, Alternative) via (ComposeEither f e)
+
+-- | Inject an 'T.ExceptT' value into the newtype wrapper.
+wrap :: T.ExceptT e m a -> ExceptT e m a
+wrap = ExceptT
+
+type Except e = ExceptT e Identity
+
+except :: Monad m => Either e a -> ExceptT e m a
+except = ExceptT . T.except
+
+runExcept :: Except e a -> Either e a
+runExcept = T.runExcept . unwrap
+
+mapExcept :: (Either e a -> Either e' b) -> Except e a -> Except e' b
+mapExcept f = ExceptT . T.mapExcept f . unwrap
+
+withExcept :: (e -> e') -> Except e a -> Except e' a
+withExcept f = ExceptT . T.withExcept f . unwrap
+
+runExceptT :: ExceptT e m a -> m (Either e a)
+runExceptT = T.runExceptT . unwrap
+
+mapExceptT :: (m (Either e a) -> n (Either e' b)) -> ExceptT e m a -> ExceptT e' n b
+mapExceptT f = ExceptT . T.mapExceptT f . unwrap
+
+withExceptT :: Functor m => (e -> e') -> ExceptT e m a -> ExceptT e' m a
+withExceptT f = ExceptT . T.withExceptT f . unwrap
+
+throwE :: Monad m => e -> ExceptT e m a
+throwE = ExceptT . T.throwE
+
+catchE :: Monad m => ExceptT e m a -> (e -> ExceptT e' m a) -> ExceptT e' m a
+catchE action continuation = ExceptT $ T.catchE (unwrap action) (unwrap . continuation)
+
+liftCallCC :: CallCC m (Either e a) (Either e b) -> CallCC (ExceptT e m) a b
+liftCallCC callCC caller = ExceptT $ T.liftCallCC callCC (unwrap . caller . (ExceptT .))
+
+liftListen :: Monad m => Listen w m (Either e a) -> Listen w (ExceptT e m) a
+liftListen listen (ExceptT action) = ExceptT $ T.liftListen listen action
+
+liftPass :: Monad m => Pass w m (Either e a) -> Pass w (ExceptT e m) a
+liftPass pass (ExceptT action) = ExceptT $ T.liftPass pass action
diff --git a/test/Laws.hs b/test/Laws.hs
--- a/test/Laws.hs
+++ b/test/Laws.hs
@@ -1,10 +1,14 @@
 {-# LANGUAGE FlexibleInstances, TupleSections, TypeApplications #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE StandaloneDeriving #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 module Laws where
 
 import Control.Arrow hiding (first, second)
+import qualified Control.Monad.Trans.Except as Transformers
 import Control.Monad.Trans.Writer
 import Control.Selective
+import Control.Selective.Trans.Except
 import Data.Bifunctor (bimap, first, second)
 import Data.Function
 import Data.Functor.Identity
@@ -146,3 +150,6 @@
 
 instance (Arbitrary w, Arbitrary a) => Arbitrary (Writer w a) where
     arbitrary = curry writer <$> arbitrary <*> arbitrary
+
+deriving instance (Arbitrary e, Arbitrary a) => Arbitrary (Transformers.Except e a)
+deriving instance (Arbitrary e, Arbitrary a) => Arbitrary (Except e a)
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -2,6 +2,7 @@
 
 import Control.Arrow (ArrowMonad)
 import Control.Monad.Trans.Writer hiding (writer)
+import Control.Selective.Trans.Except hiding (except)
 import Control.Selective
 import Data.Functor.Identity
 import Data.Maybe hiding (maybe)
@@ -28,7 +29,9 @@
     , arrowMonad
     , maybe
     , identity
-    , writer ]
+    , writer
+    , except
+    ]
 
 --------------------------------------------------------------------------------
 ------------------------ Ping-pong----------------------------------------------
@@ -386,3 +389,48 @@
         \x -> propertyPureRight @MyWriter @Int @Int x
     , expectSuccess "pure-left: pure (Left x) <*? y = ($x) <$> y" $
         \x -> propertyPureLeft @MyWriter @Int @Int x ]
+
+--------------------------------------------------------------------------------
+------------------------ Except ------------------------------------------------
+--------------------------------------------------------------------------------
+
+except :: Tests
+except = testGroup "Except"
+    [ exceptLaws
+    , exceptTheorems
+    , exceptProperties ]
+
+type MyExcept = Except [Int]
+
+exceptLaws :: Tests
+exceptLaws = testGroup "Laws"
+    [ expectSuccess "Identity: (x <*? pure id) == (either id id <$> x)" $
+        \x -> lawIdentity @MyExcept @Int x
+    , expectSuccess "Distributivity: (pure x <*? (y *> z)) == ((pure x <*? y) *> (pure x <*? z))" $
+        \x -> lawDistributivity @MyExcept @Int @Int x
+    , expectSuccess "Associativity: take a look at tests/Laws.hs" $
+        \x -> lawAssociativity @MyExcept @Int @Int @Int x
+    , expectSuccess "select == selectM" $
+        \x -> lawMonad @MyExcept @Int @Int x ]
+
+exceptTheorems :: Tests
+exceptTheorems = testGroup "Theorems"
+    [ expectSuccess "Apply a pure function to the result: (f <$> select x y) == (select (second f <$> x) ((f .) <$> y))" $
+        \x -> theorem1 @MyExcept @Int @Int @Int x
+    , expectSuccess "Apply a pure function to the Left case of the first argument: (select (first f <$> x) y) == (select x ((. f) <$> y))" $
+        \x -> theorem2 @MyExcept @Int @Int @Int x
+    , expectSuccess "Apply a pure function to the second argument: (select x (f <$> y)) == (select (first (flip f) <$> x) ((&) <$> y))" $
+        \x -> theorem3 @MyExcept @Int @Int @Int x
+    , expectSuccess "Generalised Identity: (x <*? pure y) == (either y id <$> x)" $
+        \x -> theorem4 @MyExcept @Int @Int x
+    , expectSuccess "(f <*> g) == (f `apS` g)" $
+        \x -> theorem5 @MyExcept @Int @Int x
+    , expectSuccess "Interchange: (x *> (y <*? z)) == ((x *> y) <*? z)" $
+        \x -> theorem6 @MyExcept @Int @Int @Int x ]
+
+exceptProperties :: Tests
+exceptProperties = testGroup "Properties"
+    [ expectSuccess "pure-right: pure (Right x) <*? y = pure x" $
+        \x -> propertyPureRight @MyExcept @Int @Int x
+    , expectSuccess "pure-left: pure (Left x) <*? y = ($x) <$> y" $
+        \x -> propertyPureLeft @MyExcept @Int @Int x ]
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -5,7 +5,6 @@
 import System.Exit (exitFailure)
 import Test.QuickCheck hiding (Success, Failure, expectFailure)
 
-
 data Expect = ExpectSuccess | ExpectFailure deriving Eq
 
 data Test = Test String Expect Property
@@ -23,17 +22,17 @@
 
 runTest :: [String] -> Test -> IO ()
 runTest labels (Test name expect property) = do
-    let label = intercalate "." (reverse (name : labels))
+    let label = "[" ++ intercalate "." (reverse labels) ++ "] " ++ name
     result <- quickCheckWithResult (stdArgs { chatty = False }) property
     case (expect, isSuccess result) of
-        (ExpectSuccess, True)  -> putStrLn $ "OK: " ++ label
-        (ExpectFailure, False) -> putStrLn $ "OK (expected failure): " ++ label
+        (ExpectSuccess, True) ->
+            putStrLn $ "[OK] " ++ label
+        (ExpectFailure, False) ->
+            putStrLn $ "[OK, expected failure] " ++ label
+        (ExpectFailure, True) ->
+            putStrLn $ "[Warning, unexpected success] " ++ label
         (ExpectSuccess, False) -> do
-            putStrLn $ "\nTest failure:\n    " ++ label ++ "\n"
-            putStrLn $ output result
-            exitFailure
-        (ExpectFailure, True) -> do
-            putStrLn $ "\nUnexpected test success:\n    " ++ label ++ "\n"
+            putStrLn $ "\n[Failure] " ++ label ++ "\n"
             putStrLn $ output result
             exitFailure
 
