diff --git a/lawful-conversions.cabal b/lawful-conversions.cabal
--- a/lawful-conversions.cabal
+++ b/lawful-conversions.cabal
@@ -1,7 +1,7 @@
 cabal-version: 3.0
 name: lawful-conversions
-version: 0.1.2
-synopsis: Lawful typeclasses for conversion between types
+version: 0.1.2.1
+synopsis: Lawful typeclasses for bidirectional conversion between types
 category: Conversion
 homepage: https://github.com/nikita-volkov/lawful-conversions
 bug-reports: https://github.com/nikita-volkov/lawful-conversions/issues
@@ -12,6 +12,47 @@
 license-file: LICENSE
 extra-source-files:
   CHANGELOG.md
+
+description:
+  = Summary
+
+  Lawful typeclasses capturing three patterns of bidirectional mapping and forming a layered hierarchy with an ascending strictness of laws.
+
+  1. `IsSome`: Smart constructor
+
+  2. `IsMany`: Lossy conversion
+
+  3. `Is`: Isomorphism or lossless conversion
+
+  = The conversion problem
+
+  Have you ever looked for a @toString@ function? How often do you
+  import @Data.Text.Lazy@ only to call its 'Data.Text.Lazy.fromStrict'? How
+  about importing @Data.ByteString.Builder@ only to call its
+  'Data.ByteString.Builder.toLazyByteString' and then importing
+  @Data.ByteString.Lazy@ only to call its 'Data.ByteString.Lazy.toStrict'?
+
+  Those all are instances of one pattern. They are conversions between different
+  representations of the same information. Codebases that don't attempt to
+  abstract over this pattern tend to be sprawling with this type of
+  boilerplate. It's noise to the codereader, it's a burden to the
+  implementor and the maintainer.
+
+  = Why another conversion library?
+
+  Many libraries exist that approach the conversion problem. However most of
+  them provide lawless typeclasses leaving it up to the author of the
+  instance to define what makes a proper conversion. This results in
+  inconsistencies across instances, their behaviour not being evident to
+  the user and no way to check whether an instance is correct.
+
+  This library tackles this problem with a lawful typeclass hierarchy, making it
+  evident what any of its instances do and it provides property-tests for you
+  to validate your instances.
+
+  = Prior work and acknowledgements
+
+  This library is a direct successor of the ["isomorphism-class"](https://hackage.haskell.org/package/isomorphism-class) library, expanding upon the patterns discovered there. It also shares some ideas with ["control-iso"](https://hackage.haskell.org/package/control-iso) and ["type-iso"](https://hackage.haskell.org/package/type-iso).
 
 source-repository head
   type: git
diff --git a/src/library/LawfulConversions.hs b/src/library/LawfulConversions.hs
--- a/src/library/LawfulConversions.hs
+++ b/src/library/LawfulConversions.hs
@@ -1,38 +1,4 @@
 -- |
--- Lawful typeclasses capturing three main patterns of bidirectional mapping. The typeclasses form a layered hierarchy with ascending strictness of laws.
---
--- 1. `IsSome`: Smart constructor
---
--- 2. `IsMany`: Lossy conversion
---
--- 3. `Is`: Isomorphism
---
--- = The conversion problem
---
--- Have you ever looked for a @toString@ function? How often do you
--- import @Data.Text.Lazy@ only to call its 'Data.Text.Lazy.fromStrict'? How
--- about importing @Data.ByteString.Builder@ only to call its
--- 'Data.ByteString.Builder.toLazyByteString' and then importing
--- @Data.ByteString.Lazy@ only to call its 'Data.ByteString.Lazy.toStrict'?
---
--- Those all are instances of one pattern. They are conversions between
--- representations of the same information. Codebases that don't attempt to
--- abstract over this pattern tend to be sprawling with this type of
--- boilerplate. It's noise to the codereader, it's a burden to the
--- implementor and the maintainer.
---
--- = Why another conversion library?
---
--- Many libraries exist that approach the conversion problem. However most of
--- them provide lawless typeclasses leaving it up to the author of the
--- instance to define what makes a proper conversion. This results in
--- inconsistencies across instances, their behaviour not being evident to
--- the user and no way to check whether an instance is correct.
---
--- This library tackles this problem with a lawful typeclass hierarchy, making it
--- evident what any of its instances do and it provides property-tests for you
--- to validate your instances.
---
 -- = Conversions
 --
 -- The main part of the API is two functions: 'to' and 'from'. Both
@@ -83,6 +49,35 @@
 -- - Every 'Text' can be converted into 'ByteString' via UTF-8 encoding, but not every 'ByteString' forms a valid UTF-8 sequence.
 --
 -- - Every URL can be uniquely represented as 'Text', but most 'Text's are not URLs unfortunately.
+--
+-- - UTCTime, JSON, Email, etc.
+--
+-- == Examples
+--
+-- Here's an example of implementing the Smart Constructor pattern.
+--
+-- > module Percent (Percent) where
+-- >
+-- > import LawfulConversions
+-- >
+-- > newtype Percent = Percent Double
+-- >
+-- > instance IsSome Double Percent where
+-- >   to (Percent double) = double
+-- >   maybeFrom double =
+-- >     if double < 0 || double > 1
+-- >       then Nothing
+-- >       else Just (Percent double)
+--
+-- You can also expand upon that and provide a default handling of invalid values effectively providing a lossy canonicalizing conversion ([Surjection](https://en.wikipedia.org/wiki/Surjective_function)):
+--
+-- > instance IsMany Double Percent where
+-- >   from double =
+-- >     if double < 0
+-- >       then Percent 0
+-- >       else if double > 1
+-- >         then Percent 1
+-- >         else Percent double
 module LawfulConversions
   ( -- * Typeclasses
     IsSome (..),
diff --git a/src/library/LawfulConversions/Classes.hs b/src/library/LawfulConversions/Classes.hs
--- a/src/library/LawfulConversions/Classes.hs
+++ b/src/library/LawfulConversions/Classes.hs
@@ -1,5 +1,6 @@
-module LawfulConversions.Classes (module Exports) where
+module LawfulConversions.Classes
+  ( module LawfulConversions.Classes.Is,
+  )
+where
 
-import LawfulConversions.Classes.Is as Exports
-import LawfulConversions.Classes.IsMany as Exports
-import LawfulConversions.Classes.IsSome as Exports
+import LawfulConversions.Classes.Is
diff --git a/src/library/LawfulConversions/Classes/Is.hs b/src/library/LawfulConversions/Classes/Is.hs
--- a/src/library/LawfulConversions/Classes/Is.hs
+++ b/src/library/LawfulConversions/Classes/Is.hs
@@ -1,4 +1,8 @@
-module LawfulConversions.Classes.Is where
+module LawfulConversions.Classes.Is
+  ( module LawfulConversions.Classes.Is,
+    module LawfulConversions.Classes.IsMany,
+  )
+where
 
 import LawfulConversions.Classes.IsMany
 
@@ -11,25 +15,45 @@
 --
 -- === Laws
 --
--- /B/ is isomorphic to /A/ if and only if there exists a conversion from /B/
--- to /A/ ('LawfulConversions.Classes.IsSome.to') and a conversion from /A/ to /B/ ('from') such that:
+-- ==== 'from' is an [inverse](https://en.wikipedia.org/wiki/Inverse_function) of 'to'
 --
--- - @'from' . 'LawfulConversions.Classes.IsSome.to' = 'id'@ - For all values of /B/ converting from /B/ to /A/
---     and then converting from /A/ to /B/ produces a value that is identical
---     to the original.
+-- For all values of /b/ converting from /b/ to /a/ and then converting from /a/ to /b/ produces the original value:
 --
--- - @'LawfulConversions.Classes.IsSome.to' . 'from' = 'id'@ - For all values of /A/ converting from /A/ to /B/
---     and then converting from /B/ to /A/ produces a value that is identical
---     to the original.
+-- > \b -> b == from (to @a b)
 --
+-- ==== 'to' is an [inverse](https://en.wikipedia.org/wiki/Inverse_function) of 'from'
+--
+-- For all values of /a/ converting from /a/ to /b/ and then converting from /b/ to /a/ produces the original value:
+--
+-- > \a -> a == from (to @b a)
+--
 -- === Testing
 --
 -- For testing whether your instances conform to these laws use 'LawfulConversions.isProperties'.
 --
 -- === Instance Definition
 --
--- For each pair of isomorphic types (/A/ and /B/) the compiler will require
--- you to define six instances, namely: @Is A B@ and @Is B A@, @IsMany A B@ and @IsMany B A@, @IsSome A B@ and @IsSome B A@.
+-- For each pair of isomorphic types (/A/ and /B/) the compiler will require you to define six instances, namely: @Is A B@ and @Is B A@, @IsMany A B@ and @IsMany B A@, @IsSome A B@ and @IsSome B A@.
+--
+-- Instances of @Is@ do not define any functions and serve merely as a statement that the laws are satisfied.
+--
+-- ==== __Example: Lazy Text and Text__
+--
+-- @
+-- instance IsSome 'Data.Text.Lazy.LazyText' 'Data.Text.Text' where
+--   to = LazyText.'Data.Text.Lazy.fromStrict'
+--
+-- instance IsSome 'Data.Text.Text' 'Data.Text.Lazy.LazyText' where
+--   to = LazyText.'Data.Text.Lazy.toStrict'
+--
+-- instance IsMany 'Data.Text.Lazy.LazyText' 'Data.Text.Text'
+--
+-- instance IsMany 'Data.Text.Text' 'Data.Text.Lazy.LazyText'
+--
+-- instance Is 'Data.Text.Lazy.LazyText' 'Data.Text.Text'
+--
+-- instance Is 'Data.Text.Text' 'Data.Text.Lazy.LazyText'
+-- @
 class (IsMany a b, Is b a) => Is a b
 
 -- | Any type is isomorphic to itself.
diff --git a/src/library/LawfulConversions/Classes/IsMany.hs b/src/library/LawfulConversions/Classes/IsMany.hs
--- a/src/library/LawfulConversions/Classes/IsMany.hs
+++ b/src/library/LawfulConversions/Classes/IsMany.hs
@@ -1,4 +1,8 @@
-module LawfulConversions.Classes.IsMany where
+module LawfulConversions.Classes.IsMany
+  ( module LawfulConversions.Classes.IsMany,
+    module LawfulConversions.Classes.IsSome,
+  )
+where
 
 import LawfulConversions.Classes.IsSome
 
@@ -14,31 +18,31 @@
 --
 -- === Laws
 --
--- ==== 'from' is an inverse of 'to'
+-- ==== 'from' is an [inverse](https://en.wikipedia.org/wiki/Inverse_function) of 'to'
 --
--- > \sup -> sup == from (to sup)
+-- > \b -> b == from (to @a b)
 --
 -- === Testing
 --
 -- For testing whether your instances conform to these laws use 'LawfulConversions.isManyProperties'.
-class (IsSome sup sub) => IsMany sup sub where
+class (IsSome a b) => IsMany a b where
   -- |
   -- Possibly lossy inverse of 'to'.
-  -- [Surjection](https://en.wikipedia.org/wiki/Surjective_function) from @sup@ to @sub@.
+  -- [Surjection](https://en.wikipedia.org/wiki/Surjective_function) from @a@ to @b@.
   --
   -- Particularly useful in combination with the @TypeApplications@ extension,
   -- where it allows to specify the input type, e.g.:
   --
-  -- > fromText :: IsMany Text sub => Text -> sub
+  -- > fromText :: IsMany Text b => Text -> b
   -- > fromText = from @Text
   --
   -- The first type application of the 'to' function on the other hand specifies
   -- the output data type.
-  from :: sup -> sub
+  from :: a -> b
 
   -- |
   -- Requires the presence of 'IsSome' in reverse direction.
-  default from :: (IsSome sub sup) => sup -> sub
+  default from :: (IsSome b a) => a -> b
   from = to
 
-instance IsMany sup sup
+instance IsMany a a
diff --git a/src/library/LawfulConversions/Classes/IsSome.hs b/src/library/LawfulConversions/Classes/IsSome.hs
--- a/src/library/LawfulConversions/Classes/IsSome.hs
+++ b/src/library/LawfulConversions/Classes/IsSome.hs
@@ -3,7 +3,7 @@
 import LawfulConversions.Prelude
 
 -- |
--- Evidence that all values of type @sub@ form a subset of all values of type @sup@.
+-- Evidence that all values of type @b@ form a subset of all values of type @a@.
 --
 -- [From Wikipedia](https://en.wikipedia.org/wiki/Subset):
 --
@@ -11,35 +11,33 @@
 --
 -- === Laws
 --
--- ==== 'to' is injective
+-- ==== 'to' is [injective](https://en.wikipedia.org/wiki/Injective_function)
 --
--- For every two values of type @sub@ that are not equal converting with 'to' will always produce values that are not equal.
+-- For every two values of type @b@ that are not equal converting with 'to' produces values that are not equal as well:
 --
--- > \(a, b) -> a == b || to a /= to b
+-- > \(b1, b2) -> b1 == b2 || to @a b1 /= to @a b2
 --
--- ==== 'maybeFrom' is an inverse of 'to'
+-- ==== 'maybeFrom' is a [partial inverse](https://en.wikipedia.org/wiki/Inverse_function#Partial_inverses) of 'to'
 --
--- For all values of @sub@ converting to @sup@ and then attempting to convert back to @sub@ always succeeds and produces a value that is equal to the original.
+-- For all values of @b@ converting to @a@ and then attempting to convert back to @b@ always succeeds and produces a value that is equal to the original:
 --
--- > \a -> maybeFrom (to a) == Just a
+-- > \b -> maybeFrom (to @a b) == Just b
 --
 -- === Testing
 --
 -- For testing whether your instances conform to these laws use 'LawfulConversions.isSomeProperties'.
-class IsSome sup sub where
+class IsSome a b where
   -- |
   -- Convert a value of a subset type to a superset type.
-  --
-  -- This function is injective non-surjective.
-  to :: sub -> sup
+  to :: b -> a
 
   -- |
   -- [Partial inverse](https://en.wikipedia.org/wiki/Inverse_function#Partial_inverses) of 'to'.
-  maybeFrom :: sup -> Maybe sub
+  maybeFrom :: a -> Maybe b
 
   -- |
   -- Requires the presence of 'IsSome' in reverse direction.
-  default maybeFrom :: (IsSome sub sup) => sup -> Maybe sub
+  default maybeFrom :: (IsSome b a) => a -> Maybe b
   maybeFrom = Just . to
 
 -- | Every type is isomorphic to itself.
@@ -48,6 +46,6 @@
   maybeFrom = Just . id
 
 -- | The empty set has no elements, and therefore is vacuously a subset of any set.
-instance IsSome sup Void where
+instance IsSome a Void where
   to = absurd
   maybeFrom = const Nothing
diff --git a/src/library/LawfulConversions/Properties.hs b/src/library/LawfulConversions/Properties.hs
--- a/src/library/LawfulConversions/Properties.hs
+++ b/src/library/LawfulConversions/Properties.hs
@@ -32,7 +32,7 @@
         a /= b ==>
           to' a =/= to' b
     ),
-    ( "'maybeFrom' is an inverse of 'to'",
+    ( "'maybeFrom' is a partial inverse of 'to'",
       property \a ->
         maybeFrom' (to' a) === Just a
     )
diff --git a/src/library/LawfulConversions/Proxies/ViaIsSome.hs b/src/library/LawfulConversions/Proxies/ViaIsSome.hs
--- a/src/library/LawfulConversions/Proxies/ViaIsSome.hs
+++ b/src/library/LawfulConversions/Proxies/ViaIsSome.hs
@@ -5,7 +5,7 @@
 import qualified Test.QuickCheck as QuickCheck
 
 -- |
--- Helper for deriving common instances on types which have an instance of @'IsSome' sup@ using the @DerivingVia@ extension.
+-- Helper for deriving common instances on types which have an instance of @'IsSome' a@ using the @DerivingVia@ extension.
 --
 -- E.g.,
 --
@@ -22,51 +22,51 @@
 --
 -- In the code above all the instances that are able to construct the values of 'Percent' are automatically derived based on the @IsSome Double Percent@ instance.
 -- This guarantees that they only construct values that pass thru the checks defined in 'maybeFrom'.
-newtype ViaIsSome sup sub = ViaIsSome sub
+newtype ViaIsSome a b = ViaIsSome b
 
-instance (IsSome sup sub) => IsSome sup (ViaIsSome sup sub) where
+instance (IsSome a b) => IsSome a (ViaIsSome a b) where
   to (ViaIsSome a) = to a
   maybeFrom = fmap ViaIsSome . maybeFrom
 
-instance IsSome sub (ViaIsSome sup sub) where
+instance IsSome b (ViaIsSome a b) where
   to = coerce
 
-instance IsSome (ViaIsSome sup sub) sub where
+instance IsSome (ViaIsSome a b) b where
   to = coerce
 
-instance IsMany sub (ViaIsSome sup sub)
+instance IsMany b (ViaIsSome a b)
 
-instance IsMany (ViaIsSome sup sub) sub
+instance IsMany (ViaIsSome a b) b
 
-instance Is sub (ViaIsSome sup sub)
+instance Is b (ViaIsSome a b)
 
-instance Is (ViaIsSome sup sub) sub
+instance Is (ViaIsSome a b) b
 
-instance (IsSome sup sub, Show sup) => Show (ViaIsSome sup sub) where
-  show (ViaIsSome a) = show (to @sup a)
+instance (IsSome a b, Show a) => Show (ViaIsSome a b) where
+  show (ViaIsSome a) = show (to @a a)
 
-instance (IsSome sup sub, Read sup) => Read (ViaIsSome sup sub) where
+instance (IsSome a b, Read a) => Read (ViaIsSome a b) where
   readPrec = do
-    sup <- readPrec
-    case maybeFrom @sup sup of
+    a <- readPrec
+    case maybeFrom @a a of
       Just a -> pure (ViaIsSome a)
       Nothing -> fail "Value is not from the subset"
 
-instance (IsSome sup sub, IsString sup) => IsString (ViaIsSome sup sub) where
+instance (IsSome a b, IsString a) => IsString (ViaIsSome a b) where
   fromString =
-    maybe (error "Value is not from the subset") ViaIsSome . maybeFrom @sup . fromString
+    maybe (error "Value is not from the subset") ViaIsSome . maybeFrom @a . fromString
 
-instance (IsSome sup sub, Eq sup) => Eq (ViaIsSome sup sub) where
-  (==) = on (==) (to @sup)
+instance (IsSome a b, Eq a) => Eq (ViaIsSome a b) where
+  (==) = on (==) (to @a)
 
-instance (IsSome sup sub, Ord sup) => Ord (ViaIsSome sup sub) where
-  compare = on compare (to @sup)
+instance (IsSome a b, Ord a) => Ord (ViaIsSome a b) where
+  compare = on compare (to @a)
 
-instance (IsSome sup sub, QuickCheck.Arbitrary sup) => QuickCheck.Arbitrary (ViaIsSome sup sub) where
+instance (IsSome a b, QuickCheck.Arbitrary a) => QuickCheck.Arbitrary (ViaIsSome a b) where
   arbitrary =
-    QuickCheck.suchThatMap QuickCheck.arbitrary (maybeFrom @sup)
+    QuickCheck.suchThatMap QuickCheck.arbitrary (maybeFrom @a)
   shrink value = do
-    shrunkValue <- QuickCheck.shrink (to @sup value)
+    shrunkValue <- QuickCheck.shrink (to @a value)
     shrunkValue
       & maybeFrom
       & maybeToList
