diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,4 +8,22 @@
 
 ## Unreleased
 
-## 0.1.0.0 - YYYY-MM-DD
+## 0.1.0.5 - 2025-02-05
+
+- Relax max allowed versions of DeepSeq (<1.6), Hashable (<1.6), QuickCheck (<2.16)
+
+## 0.1.0.4 - 2024-01-15
+
+- Improved test coverage for exception cases; README is now fully tested using Literate Haskell.
+
+## 0.1.0.3 - 2024-01-14
+
+- Fix a typographic error in the documentation
+
+## 0.1.0.2 - 2024-01-14
+
+- Improve documentation
+
+## 0.1.0.0 - 2024-01-13
+
+- Initial version
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -9,10 +9,23 @@
 
 Just like tuples are a version of a user-defined product type (only without the field names), a Variant is a version of a user-defined sum type (but without the field names).
 
-Variant types are the generalization of `Either`. Especially in the situation where you want to handle multiple errors, Variant types are a great abstraction to use.
+In other words: Variant types are the generalization of `Either` to more (or less) than two alternatives. 
 
+| Product:     | Sum:                     |
+|--------------|--------------------------|
+| ()           | Vary [] / Void           |
+| Solo a       | Vary [a]                 |
+| (a, b)       | Vary [a, b] / Either a b |
+| (a, b, c)    | Vary [a, b, c]           |
+| (a, b, c, d) | Vary [a, b, c, d]        |
+| (...)        | Vary [...]               |
+
+Especially when doing error handling (both in pure code and in exception-heavy code), Variant types are a great abstraction to use.
+
 Variant types are sometimes called '_polymorphic_ variants' for disambiguation. They are also commonly known as (open) unions, coproducts or extensible sums.
 
+Vary is lightweight on dependencies. With all library flags turned off, it only depends on `base` and `deepseq`.
+
 ## General Usage
 
 ### Setup
@@ -103,6 +116,7 @@
      * This can fail, because the downloaded file might turn out actually not to be a valid image file (PNG or JPG);
      * Or even if the downloaded file /is/ an image, it might have a much too high resolution to attempt to read;
 
+_(NOTE: For simplicity, we pretend everything is a pure function rather than using IO or some more fancy effect stack in the examples below.)_
 
  The first instinct might be to write dedicated sum types for these errors like so:
 
@@ -235,10 +249,11 @@
 ```haskell
 thumbnailServiceRetry :: String -> VEither [IncorrectUrl2, NotAnImage2, TooBigImage2] Image
 thumbnailServiceRetry url = do
-  image <- download url 
-           & VEither.onLeft (\ServerUnreachable2 -> waitAndRetry 10 (\_ -> thumbnailServiceRetry url)) id
+  image <- VEither.handle @ServerUnreachable2 retry $ download url
   thumb <- thumbnail image
   pure thumb
+  where
+    retry _err = waitAndRetry 10 (\_ -> thumbnailServiceRetry url)
 ```
 
 - No more wrapper type definitions!
@@ -276,6 +291,8 @@
   - Only the most widely-useful functions are provided in `Vary` itself. There are some extra functions in `Vary.Utils` which are intentionally left out of the main module to make it more digestible for new users. 
 - Libraries are already many years old (with no newer updates), and so they are not using any of the newer GHC extensions or inference improvements.
   - `Vary` makes great use of the `GHC2021` group of extensions, TypeFamilies and the `TypeError` construct to make most type errors disappear and for the few that remain it should be easy to understand how to fix them.
+- None of the libraries make an attempt to work well with Haskell's exception mechanisms.
+  - `Vary` [has excellent support to be thrown and caught as exceptions](https://hackage.haskell.org/package/vary/docs/Vary.html#vary_and_exceptions).
 
 ## Acknowledgements
 
diff --git a/src/Vary.hs b/src/Vary.hs
--- a/src/Vary.hs
+++ b/src/Vary.hs
@@ -20,6 +20,7 @@
 {-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE NoStarIsType #-}
+{-# LANGUAGE EmptyCase #-}
 
 module Vary
   ( -- * General Usage
@@ -364,7 +365,7 @@
 --   & Vary.intoOnly              -- String
 -- :}
 -- "True"
---
+
 -- Note that if you end up handling all cases of a variant, you might prefer using `Vary.on` and `Vary.exhaustiveCase` instead.
 --
 -- == Generic code
@@ -391,3 +392,4 @@
   case into @a vary of
     Just a -> from @b (fun a)
     Nothing -> (Vary tag val)
+
diff --git a/src/Vary/Core.hs b/src/Vary/Core.hs
--- a/src/Vary/Core.hs
+++ b/src/Vary/Core.hs
@@ -1,17 +1,35 @@
 {-# LANGUAGE GHC2021 #-}
-{-# OPTIONS_HADDOCK not-home #-}
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE UndecidableInstances #-}
-{-# LANGUAGE MonoLocalBinds #-}
+{-# OPTIONS_HADDOCK not-home #-}
+
 module Vary.Core (Vary (..), pop) where
 
-import Data.Kind (Type)
-import GHC.Exts (Any)
-import qualified Unsafe.Coerce as Data.Coerce
+import Control.Applicative ((<|>))
 import Control.DeepSeq (NFData (..))
-import Control.Exception (Exception(..))
+import Control.Exception (Exception (..))
+import Data.Kind (Type)
 import Data.Typeable (Typeable, typeOf)
+import GHC.Exts (Any)
+import GHC.Generics
+import Unsafe.Coerce qualified as Data.Coerce
 
+# ifdef FLAG_AESON
+import Data.Aeson qualified as Aeson
+# endif
+
+# ifdef FLAG_HASHABLE
+import Data.Hashable
+# endif
+
+# ifdef FLAG_QUICKCHECK
+import Test.QuickCheck
+import Test.QuickCheck.Arbitrary (GSubterms, RecursivelyShrink)
+# endif
+
 -- $setup
 -- >>> :set -XGHC2021
 -- >>> :set -XDataKinds
@@ -40,7 +58,6 @@
 emptyVaryError :: forall anything. String -> Vary '[] -> anything
 emptyVaryError name = error (name <> " was called on empty Vary '[]")
 
-
 -- | Attempts to extract a value of the first type from the `Vary`.
 --
 -- If this failed, we know it has to be one of the other possibilities.
@@ -60,31 +77,39 @@
 -- >        Right val -> "Vary.from " <> show val
 -- >        Left other -> show other
 --
--- To go the other way: 
+-- To go the other way:
 --
 -- - Use "Vary".`Vary.morph` to turn @Vary as@ back into @Vary (a : as)@
 -- - Use "Vary".`Vary.from` to turn @a@ back into @Vary (a : as)@
 pop :: Vary (a : as) -> Either (Vary as) a
 {-# INLINE pop #-}
 pop (Vary 0 val) = Right (Data.Coerce.unsafeCoerce val)
-pop (Vary tag val) = Left (Data.Coerce.unsafeCoerce (Vary (tag - 1) val))
+pop (Vary tag inner) = Left (Vary (tag - 1) inner)
 
+pushHead :: a -> Vary (a : as)
+{-# INLINE pushHead #-}
+pushHead val = Vary 0 (Data.Coerce.unsafeCoerce val)
+
+{-# INLINE pushTail #-}
+pushTail :: Vary as -> Vary (a : as)
+pushTail (Vary tag inner) = Vary (tag + 1) inner
+
 instance Eq (Vary '[]) where
   (==) = emptyVaryError "Eq.(==)"
 
 instance (Eq a, Eq (Vary as)) => Eq (Vary (a : as)) where
-    {-# INLINE (==) #-}
-    a == b = pop a == pop b
+  {-# INLINE (==) #-}
+  a == b = pop a == pop b
 
 instance Ord (Vary '[]) where
-    compare = emptyVaryError "Ord.compare"
+  compare = emptyVaryError "Ord.compare"
 
 instance (Ord a, Ord (Vary as)) => Ord (Vary (a : as)) where
-    {-# INLINE compare #-}
-    l `compare` r = pop l `compare` pop r
+  {-# INLINE compare #-}
+  l `compare` r = pop l `compare` pop r
 
 instance Show (Vary '[]) where
-    show = emptyVaryError "Show.show"
+  show = emptyVaryError "Show.show"
 
 -- | `Vary`'s 'Show' instance only works for types which are 'Typeable'
 --
@@ -97,40 +122,173 @@
 -- >>> Vary.from @(Maybe Int) (Just 1234) :: Vary '[Maybe Int, Bool]
 -- Vary.from @(Maybe Int) (Just 1234)
 instance (Typeable a, Show a, Show (Vary as)) => Show (Vary (a : as)) where
-    showsPrec d vary = case pop vary of
-        Right val ->
-            showString "Vary.from " . 
-            showString "@" . 
-            showsPrec (d+10) (typeOf val) . 
-            showString " " . 
-            showsPrec (d+11) val
-        Left other -> showsPrec d other
+  showsPrec d vary = case pop vary of
+    Right val ->
+      showString "Vary.from "
+        . showString "@"
+        . showsPrec (d + 10) (typeOf val)
+        . showString " "
+        . showsPrec (d + 11) val
+    Left other -> showsPrec d other
 
 instance NFData (Vary '[]) where
-    rnf = emptyVaryError "NFData.rnf"
+  rnf = emptyVaryError "NFData.rnf"
 
 instance (NFData a, NFData (Vary as)) => NFData (Vary (a : as)) where
-    {-# INLINE rnf #-}
-    rnf vary = rnf (pop vary)
-
+  {-# INLINE rnf #-}
+  rnf vary = rnf (pop vary)
 
-instance (Typeable (Vary '[]), Show (Vary '[])) => Exception (Vary '[]) where
+instance (Typeable (Vary '[]), Show (Vary '[])) => Exception (Vary '[])
 
 -- | See [Vary and Exceptions](#vary_and_exceptions) for more info.
 instance (Exception e, Exception (Vary errs), Typeable errs) => Exception (Vary (e : errs)) where
-    displayException vary = 
-        case pop vary of
-            Right val -> displayException val
-            Left rest -> displayException rest
+  displayException vary =
+    either displayException displayException (pop vary)
 
-    toException vary = 
-        case pop vary of
-            Right val -> toException val
-            Left rest -> toException rest
-    
-    fromException some_exception = 
-        case fromException @e some_exception of
-            Just e -> Just (Vary 0 (Data.Coerce.unsafeCoerce e))
-            Nothing -> case fromException @(Vary errs) some_exception of
-                Just (Vary tag err) -> Just (Data.Coerce.unsafeCoerce (Vary (tag+1) err))
-                Nothing -> Nothing
+  toException vary =
+    either toException toException (pop vary)
+
+  fromException ex =
+    (pushHead <$> fromException @e ex) <|> (pushTail <$> fromException @(Vary errs) ex)
+
+-- case fromException @e some_exception of
+--     Just e -> Just (pushHead e)
+--     Nothing ->
+--       case fromException @(Vary errs) some_exception of
+--         Just vary -> Just (pushTail vary)
+--         Nothing -> Nothing
+
+-- Behold! A manually-written Generic instance!
+--
+-- This instance is very similar to the one for tuples (), (,), (,,), ...
+-- but with each occurrence of :*: replaced by :+:
+-- (and using `V1` instead of `U1` for the empty Vary)
+type family RepHelper (list :: [Type]) :: Type -> Type where
+  RepHelper '[] = V1
+  RepHelper '[a] =
+    S1
+      ( MetaSel
+          Nothing
+          NoSourceUnpackedness
+          NoSourceStrictness
+          DecidedLazy
+      )
+      (K1 R a)
+  RepHelper (a : b : bs) =
+    S1
+      (MetaSel Nothing NoSourceUnpackedness NoSourceStrictness DecidedLazy)
+      (Rec0 a)
+      :+: RepHelper (b : bs)
+
+class GenericHelper (list :: [Type]) where
+  fromHelper :: Vary list -> (RepHelper list) x
+  toHelper :: (RepHelper list) x -> Vary list
+
+instance GenericHelper '[] where
+  fromHelper = emptyVaryError "Generic.from"
+  toHelper void = case void of {}
+
+instance GenericHelper '[a] where
+  fromHelper vary = case pop vary of
+    Right val -> M1 $ K1 $ val
+    Left empty -> emptyVaryError "Generic.from" empty
+
+  toHelper (M1 (K1 val)) = pushHead val
+
+instance (GenericHelper (b : bs)) => GenericHelper (a : b : bs) where
+  fromHelper vary = case pop vary of
+    Right val -> L1 $ M1 $ K1 $ val
+    Left rest -> R1 $ fromHelper rest
+
+  toHelper (L1 (M1 (K1 val))) = pushHead val
+  toHelper (R1 rest) = pushTail (toHelper rest)
+
+-- | Vary '[] 's generic representation is `V1`.
+instance Generic (Vary '[]) where
+  type
+    Rep (Vary '[]) =
+      D1
+        (MetaData "Vary" "Vary" "vary" False)
+        (RepHelper '[])
+  from = emptyVaryError "Generic.from"
+  to void = case void of {}
+
+-- | Any non-empty Vary's generic representation is encoded similar to a tuple but with `:+:` instead of `:*:`.
+instance (GenericHelper (a : as)) => Generic (Vary (a : as)) where
+  type
+    Rep (Vary (a : as)) =
+      D1
+        (MetaData "Vary" "Vary" "vary" False)
+        ( C1
+            (MetaCons "from" PrefixI False)
+            (RepHelper (a : as))
+        )
+  from vary = M1 $ M1 $ fromHelper vary
+  to (M1 (M1 gval)) = toHelper gval
+
+# ifdef FLAG_AESON
+deriving instance Aeson.FromJSON (Vary '[])
+
+deriving instance (Aeson.FromJSON a) => Aeson.FromJSON (Vary '[a])
+
+instance (Aeson.FromJSON a, Aeson.FromJSON (Vary (b : bs))) => Aeson.FromJSON (Vary (a : b : bs)) where
+  {-# INLINE parseJSON #-}
+  parseJSON val = (pushHead <$> Aeson.parseJSON val) <|> (pushTail <$> Aeson.parseJSON val)
+
+deriving instance Aeson.ToJSON (Vary '[])
+
+deriving instance (Aeson.ToJSON a) => Aeson.ToJSON (Vary '[a])
+
+instance (Aeson.ToJSON a, Aeson.ToJSON (Vary (b : bs))) => Aeson.ToJSON (Vary (a : b : bs)) where
+  {-# INLINE toJSON #-}
+  toJSON vary =
+    either Aeson.toJSON Aeson.toJSON (pop vary)
+
+  {-# INLINE toEncoding #-}
+  toEncoding vary =
+    either Aeson.toEncoding Aeson.toEncoding (pop vary)
+# endif
+
+# ifdef FLAG_QUICKCHECK
+instance (Test.QuickCheck.Arbitrary a) => Test.QuickCheck.Arbitrary (Vary '[a]) where
+  arbitrary = pushHead <$> arbitrary
+  shrink = genericShrink
+
+instance
+  ( Arbitrary a,
+    Arbitrary (Vary (b : bs)),
+    Generic (Vary (a : b : bs)),
+    RecursivelyShrink (Rep (Vary (a : b : bs))),
+    GSubterms (Rep (Vary (a : b : bs))) (Vary (a : b : bs))
+  ) =>
+  Test.QuickCheck.Arbitrary (Vary (a : b : bs))
+  where
+  arbitrary = oneof [pushHead <$> arbitrary, pushTail <$> arbitrary]
+  shrink = genericShrink
+# endif
+
+#ifdef FLAG_HASHABLE
+class FastHashable a where
+  badHashWithSalt :: Int -> a -> Int
+
+instance (Hashable a) => FastHashable (Vary '[a]) where
+  {-# INLINE badHashWithSalt #-}
+  badHashWithSalt salt vary = case pop vary of
+    Right val -> hashWithSalt salt val
+    Left empty -> emptyVaryError "hashWithSalt" empty
+
+instance (Hashable a, FastHashable (Vary (b : bs))) => FastHashable (Vary (a : b : bs)) where
+  {-# INLINE badHashWithSalt #-}
+  badHashWithSalt salt vary = case pop vary of
+    Right val -> hashWithSalt salt val
+    Left rest -> badHashWithSalt salt rest
+
+instance
+  ( Eq (Vary (a : as)),
+    FastHashable (Vary (a : as))
+  ) =>
+  Hashable (Vary (a : as))
+  where
+  hashWithSalt salt vary@(Vary tag _inner) = fromIntegral tag `hashWithSalt` badHashWithSalt salt vary
+  hash vary@(Vary tag _inner) = badHashWithSalt (fromIntegral tag) vary
+#endif
diff --git a/src/Vary/VEither.hs b/src/Vary/VEither.hs
--- a/src/Vary/VEither.hs
+++ b/src/Vary/VEither.hs
@@ -3,6 +3,8 @@
 {-# LANGUAGE PatternSynonyms #-}
 {-# LANGUAGE ViewPatterns #-}
 {-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE UndecidableInstances #-}
 module Vary.VEither (
   -- * General Usage
   -- $setup
@@ -28,6 +30,7 @@
   -- similar to "Vary".'Vary.on' and co.
   onLeft,
   onRight,
+  handle,
 
   -- * Transforming
   mapLeftOn,
@@ -47,6 +50,18 @@
 import qualified Vary
 import GHC.Generics
 
+# ifdef FLAG_AESON
+import Data.Aeson qualified as Aeson
+# endif
+
+# ifdef FLAG_HASHABLE
+import Data.Hashable
+# endif
+
+# ifdef FLAG_QUICKCHECK
+import Test.QuickCheck
+# endif
+
 -- $setup
 --
 -- This module is intended to be used qualified:
@@ -58,15 +73,24 @@
 --
 -- >>> :set -XGHC2021
 -- >>> :set -XDataKinds
+--
+-- Finally, some example snippets in this module make use of 'Data.Function.&', the left-to-right function application operator.
+--
+-- >>> import Data.Function ((&))
 
+
 newtype VEither (errs :: [Type]) a = VEither (Vary (a : errs))
 
 -- | Turns the 'VEither' into a normal Vary, no longer considering the @a@ a \'preferred\' value.
+--
+-- In many cases, you probably want to mattern match on "VEither".'VLeft' instead!
 toVary :: VEither errs a -> Vary (a : errs)
 {-# INLINE toVary #-}
 toVary (VEither vary) = vary
 
 -- | Turns a 'Vary' into a 'VEither'. Now the @a@ is considered the \'preferred\' value.
+--
+-- In many cases, you probably want to use "VEither".'VLeft' instead!
 fromVary :: Vary (a : errs) -> VEither errs a
 {-# INLINE fromVary #-}
 fromVary vary = VEither vary
@@ -93,56 +117,97 @@
 -- >>> VEither.fromLeft @Bool True :: VEither '[Bool] String
 -- VLeft (Vary.from @Bool True) 
 fromLeft :: forall err errs a. err :| errs => err -> VEither errs a
+{-# INLINE fromLeft #-}
 fromLeft = Vary.from @err >>> VLeft
 
 -- | Construct a 'VEither' from an @a@.
 --
 -- Exists for symmetry with 'fromLeft'.
--- Indeed, this is just another name for 'VRight'.
+-- Indeed, this is just another name for 'VRight' (and for 'pure').
 fromRight :: forall a errs. a -> VEither errs a
+{-# INLINE fromRight #-}
 fromRight = VRight
 
 -- | Case analysis on a 'VEither'. Similar to 'Data.Either.either'.
 --
 -- See also "VEither".'mapLeft', "VEither".'mapLeftOn' and "VEither".'mapRight'.
 veither :: (Vary errs -> c) -> (a -> c) -> VEither errs a -> c
+{-# INLINE veither #-}
 veither f _ (VLeft x)     =  f x
 veither _ g (VRight y)    =  g y
 
 {-# COMPLETE VLeft, VRight #-}
 
+-- Matches when the VEither contains one of the errors, returning @Vary errs@
 pattern VLeft :: forall a errs. Vary errs -> VEither errs a
 {-# INLINE VLeft #-}
 pattern VLeft errs <- (toEither -> Left errs)
    where
       VLeft (Vary tag err) = VEither ((Vary (tag+1) err))
 
+-- | Matches when the VEither contains the preferred value of type @a@.
 pattern VRight :: forall a errs. a -> VEither errs a
 {-# INLINE VRight #-}
 pattern VRight a <- (toEither -> Right a)
   where
     VRight a = VEither (Vary.from @a a)
 
+-- | Handle a particular error possibility.
+--
+-- Works very similarly to "Vary".'Vary.on'.
 onLeft :: forall err b errs a. (err -> b) -> (VEither errs a -> b) -> VEither (err : errs) a -> b
+{-# INLINE onLeft #-}
 onLeft thiserrFun restfun ve = case ve of
   VLeft e -> Vary.on @err thiserrFun (\otherErr -> restfun (VLeft otherErr)) e
   VRight a -> restfun (VRight a)
 
+-- | Handle the success posibility.
+--
+--
+-- Works very similarly to "Vary".'Vary.on'.
+-- Usually used together with "VError".'onLeft'.
 onRight :: (a -> b) -> (VEither errs a -> b) -> VEither errs a -> b
+{-# INLINE onRight #-}
 onRight valfun restfun ve = case ve of
   VRight a -> valfun a
   VLeft err -> restfun (VLeft err)
 
+-- | Handle a single error, by mapping it either to the success type @a@ or to one of the other errors in @errs@.
+--
+-- This is syntactic sugar over using "VEither".'onLeft',
+-- but can be nicer to use if one or only a few error variants need to be handled,
+-- because it lets you build a simple pipeline:
+--
+-- >>> :{
+--  examplePipe ve = ve
+--    & VEither.handle @Int (pure . show) 
+--    & VEither.handle @Bool (pure . show)
+-- :}
+--
+-- >>> :t examplePipe
+-- examplePipe 
+--   :: VEither (Int : Bool : errs) String -> VEither errs String
+-- >>> examplePipe (VEither.fromLeft False :: VEither '[Int, Bool, Float] String)
+-- VRight "False"
+handle :: (err -> VEither errs a) -> VEither (err : errs) a -> VEither errs a
+{-# INLINE handle #-}
+handle fun = onLeft fun id
+
 -- | If you have a VEither which does not actually contain any errors,
 -- you can be sure it always contains an @a@.
 --
 -- Similar to "Vary".'Vary.intoOnly'.
 intoOnly :: forall a. VEither '[] a -> a
+{-# INLINE intoOnly #-}
 intoOnly (VRight a) = a
 intoOnly (VLeft emptyVary) = Vary.exhaustiveCase emptyVary
 
 
+-- | Extend a smaller `VEiher` into a bigger one, change the order of its error types, or get rid of duplicate error types.
+--
+-- Similar to "Vary".'Vary.morph'
 morph :: forall ys xs a. Subset (a : xs) (a : ys) => VEither xs a -> VEither ys a
+{-# INLINE morph #-}
 morph = toVary >>> Vary.morph >>> fromVary
 
 -- | Execute a function expecting a larger (or differently-ordered) variant
@@ -158,6 +223,7 @@
 --
 -- Similar to "Vary".'Vary.mapOn'.
 mapLeftOn :: forall x y xs ys a. (Mappable x y xs ys) => (x -> y) -> VEither xs a -> VEither ys a
+{-# INLINE mapLeftOn #-}
 mapLeftOn _ (VRight val) = VRight val
 mapLeftOn fun (VLeft err) = VLeft $ Vary.mapOn fun err
 
@@ -166,6 +232,7 @@
 -- See also "VEither".'mapLeftOn', "VEither".'mapRight' and "VEither".'veither'.
 --
 mapLeft :: (Vary xs -> Vary ys) -> VEither xs a -> VEither ys a
+{-# INLINE mapLeft #-}
 mapLeft fun ve = case ve of 
     VRight a -> VRight a
     VLeft errs -> VLeft (fun errs)
@@ -178,6 +245,7 @@
 --
 -- See also "VEither".'veither'.
 mapRight :: (x -> y) -> VEither errs x -> VEither errs y
+{-# INLINE mapRight #-}
 mapRight fun ve = case ve of 
     VRight a -> VRight (fun a)
     VLeft errs -> VLeft errs
@@ -232,7 +300,10 @@
   (VRight a) <> _ = (VRight a)
   _ <> b = b
 
--- Look ma! A Hand-written Generic instance!
+-- Look! A hand-written Generic instance! ;-)
+--
+-- This closely follows the implementation of the normal Either,
+-- and pretends the type truly is built up of VLeft and VRight
 instance Generic (VEither errs a) where
   type (Rep (VEither errs a)) =  D1
        (MetaData "VEither" "Vary.VEither" "vary" False)
@@ -257,8 +328,8 @@
 
   to :: Rep (VEither errs a) x -> VEither errs a 
   to rep = case rep of
-    (M1 (L1 (M1 (M1 (K1 err))))) -> (VLeft err)
-    (M1 (R1 (M1 (M1 (K1 val))))) -> (VRight val)
+    (M1 (L1 (M1 (M1 (K1 err))))) -> VLeft err
+    (M1 (R1 (M1 (M1 (K1 val))))) -> VRight val
 
 
 -- Conceptually VEither is a Bifunctor,
@@ -270,3 +341,16 @@
 --   first = mapLeft
 --   second = mapRight
 --   bimap = veither
+
+#ifdef FLAG_HASHABLE 
+instance (Hashable a, Hashable (Vary errs), (Eq (VEither errs a))) => Hashable (VEither errs a)
+#endif
+
+#ifdef FLAG_AESON 
+deriving instance Aeson.ToJSON (Vary (a : errs)) => Aeson.ToJSON (VEither errs a)
+deriving instance Aeson.FromJSON (Vary (a : errs)) => Aeson.FromJSON (VEither errs a)
+#endif
+
+#ifdef FLAG_QUICKCHECK
+deriving instance (Arbitrary (Vary (a : errs))) => Test.QuickCheck.Arbitrary (VEither errs a)
+#endif
diff --git a/test/README.lhs b/test/README.lhs
--- a/test/README.lhs
+++ b/test/README.lhs
@@ -9,10 +9,23 @@
 
 Just like tuples are a version of a user-defined product type (only without the field names), a Variant is a version of a user-defined sum type (but without the field names).
 
-Variant types are the generalization of `Either`. Especially in the situation where you want to handle multiple errors, Variant types are a great abstraction to use.
+In other words: Variant types are the generalization of `Either` to more (or less) than two alternatives. 
 
+| Product:     | Sum:                     |
+|--------------|--------------------------|
+| ()           | Vary [] / Void           |
+| Solo a       | Vary [a]                 |
+| (a, b)       | Vary [a, b] / Either a b |
+| (a, b, c)    | Vary [a, b, c]           |
+| (a, b, c, d) | Vary [a, b, c, d]        |
+| (...)        | Vary [...]               |
+
+Especially when doing error handling (both in pure code and in exception-heavy code), Variant types are a great abstraction to use.
+
 Variant types are sometimes called '_polymorphic_ variants' for disambiguation. They are also commonly known as (open) unions, coproducts or extensible sums.
 
+Vary is lightweight on dependencies. With all library flags turned off, it only depends on `base` and `deepseq`.
+
 ## General Usage
 
 ### Setup
@@ -103,6 +116,7 @@
      * This can fail, because the downloaded file might turn out actually not to be a valid image file (PNG or JPG);
      * Or even if the downloaded file /is/ an image, it might have a much too high resolution to attempt to read;
 
+_(NOTE: For simplicity, we pretend everything is a pure function rather than using IO or some more fancy effect stack in the examples below.)_
 
  The first instinct might be to write dedicated sum types for these errors like so:
 
@@ -235,10 +249,11 @@
 ```haskell
 thumbnailServiceRetry :: String -> VEither [IncorrectUrl2, NotAnImage2, TooBigImage2] Image
 thumbnailServiceRetry url = do
-  image <- download url 
-           & VEither.onLeft (\ServerUnreachable2 -> waitAndRetry 10 (\_ -> thumbnailServiceRetry url)) id
+  image <- VEither.handle @ServerUnreachable2 retry $ download url
   thumb <- thumbnail image
   pure thumb
+  where
+    retry _err = waitAndRetry 10 (\_ -> thumbnailServiceRetry url)
 ```
 
 - No more wrapper type definitions!
@@ -276,6 +291,8 @@
   - Only the most widely-useful functions are provided in `Vary` itself. There are some extra functions in `Vary.Utils` which are intentionally left out of the main module to make it more digestible for new users. 
 - Libraries are already many years old (with no newer updates), and so they are not using any of the newer GHC extensions or inference improvements.
   - `Vary` makes great use of the `GHC2021` group of extensions, TypeFamilies and the `TypeError` construct to make most type errors disappear and for the few that remain it should be easy to understand how to fix them.
+- None of the libraries make an attempt to work well with Haskell's exception mechanisms.
+  - `Vary` [has excellent support to be thrown and caught as exceptions](https://hackage.haskell.org/package/vary/docs/Vary.html#vary_and_exceptions).
 
 ## Acknowledgements
 
diff --git a/vary.cabal b/vary.cabal
--- a/vary.cabal
+++ b/vary.cabal
@@ -1,11 +1,11 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.36.0.
+-- This file has been generated from package.yaml by hpack version 0.35.2.
 --
 -- see: https://github.com/sol/hpack
 
 name:           vary
-version:        0.1.0.3
+version:        0.1.0.5
 synopsis:       Vary: Friendly and fast polymorphic variants (open unions/coproducts/extensible sums)
 description:    Vary: Friendly and fast Variant types for Haskell
                 .
@@ -15,6 +15,8 @@
                 .
                 Variant types are sometimes called '_polymorphic_ variants' for disambiguation. They are also commonly known as (open) unions, coproducts or extensible sums.
                 .
+                Vary is lightweight on dependencies. With all library flags turned off, it only depends on `base` and `deepseq`.
+                .
                 Please see the full README below or on GitHub at <https://github.com/qqwy/haskell-vary#readme>
 category:       Data, Data Structures, Error Handling
 homepage:       https://github.com/qqwy/haskell-vary#readme
@@ -33,6 +35,21 @@
   type: git
   location: https://github.com/qqwy/haskell-vary
 
+flag aeson
+  description: When enabled implements the @FromJSON@/@ToJSON@ typeclasses from the aeson library. When disabled, does not depend on the aeson library.
+  manual: True
+  default: True
+
+flag hashable
+  description: When enabled implements the @Hashable@ typeclass from the hashable library. When disabled, does not depend on the @hashable@ library.
+  manual: True
+  default: True
+
+flag quickcheck
+  description: When enabled implements the @Arbitrary@ typeclasses from the QuickCheck library. When disabled, does not depend on the QuickCheck library.
+  manual: True
+  default: True
+
 library
   exposed-modules:
       Vary
@@ -45,8 +62,20 @@
   ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints
   build-depends:
       base >=4.7 && <5
-    , deepseq >=1.4.0 && <1.5
+    , deepseq >=1.4.0 && <1.6
   default-language: Haskell2010
+  if flag(hashable)
+    cpp-options: -DFLAG_HASHABLE
+    build-depends:
+        hashable >=1.3.0 && <1.6
+  if flag(aeson)
+    cpp-options: -DFLAG_AESON
+    build-depends:
+        aeson >=2.0.0 && <2.3
+  if flag(quickcheck)
+    cpp-options: -DFLAG_QUICKCHECK
+    build-depends:
+        QuickCheck >=2.12 && <2.16
 
 test-suite doctests
   type: exitcode-stdio-1.0
@@ -58,10 +87,22 @@
   ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
   build-depends:
       base >=4.7 && <5
-    , deepseq >=1.4.0 && <1.5
+    , deepseq >=1.4.0 && <1.6
     , doctest-parallel
     , vary
   default-language: Haskell2010
+  if flag(hashable)
+    cpp-options: -DFLAG_HASHABLE
+    build-depends:
+        hashable >=1.3.0 && <1.6
+  if flag(aeson)
+    cpp-options: -DFLAG_AESON
+    build-depends:
+        aeson >=2.0.0 && <2.3
+  if flag(quickcheck)
+    cpp-options: -DFLAG_QUICKCHECK
+    build-depends:
+        QuickCheck >=2.12 && <2.16
 
 test-suite readme
   type: exitcode-stdio-1.0
@@ -73,12 +114,24 @@
       markdown-unlit:markdown-unlit
   build-depends:
       base >=4.7 && <5
-    , deepseq >=1.4.0 && <1.5
+    , deepseq >=1.4.0 && <1.6
     , hspec
     , markdown-unlit
     , should-not-typecheck
     , vary
   default-language: Haskell2010
+  if flag(hashable)
+    cpp-options: -DFLAG_HASHABLE
+    build-depends:
+        hashable >=1.3.0 && <1.6
+  if flag(aeson)
+    cpp-options: -DFLAG_AESON
+    build-depends:
+        aeson >=2.0.0 && <2.3
+  if flag(quickcheck)
+    cpp-options: -DFLAG_QUICKCHECK
+    build-depends:
+        QuickCheck >=2.12 && <2.16
 
 test-suite vary-test
   type: exitcode-stdio-1.0
@@ -90,6 +143,18 @@
   ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
   build-depends:
       base >=4.7 && <5
-    , deepseq >=1.4.0 && <1.5
+    , deepseq >=1.4.0 && <1.6
     , vary
   default-language: Haskell2010
+  if flag(hashable)
+    cpp-options: -DFLAG_HASHABLE
+    build-depends:
+        hashable >=1.3.0 && <1.6
+  if flag(aeson)
+    cpp-options: -DFLAG_AESON
+    build-depends:
+        aeson >=2.0.0 && <2.3
+  if flag(quickcheck)
+    cpp-options: -DFLAG_QUICKCHECK
+    build-depends:
+        QuickCheck >=2.12 && <2.16
