diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2022 Nikita Volkov
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/lawful-conversions.cabal b/lawful-conversions.cabal
new file mode 100644
--- /dev/null
+++ b/lawful-conversions.cabal
@@ -0,0 +1,121 @@
+cabal-version: 3.0
+name: lawful-conversions
+version: 0.1
+synopsis: Lawful typeclasses for conversion between types
+category: Conversion
+homepage: https://github.com/nikita-volkov/lawful-conversions
+bug-reports: https://github.com/nikita-volkov/lawful-conversions/issues
+author: Nikita Volkov <nikita.y.volkov@mail.ru>
+maintainer: Nikita Volkov <nikita.y.volkov@mail.ru>
+copyright: (c) 2022 Nikita Volkov
+license: MIT
+license-file: LICENSE
+extra-source-files:
+  CHANGELOG.md
+
+source-repository head
+  type: git
+  location: git://github.com/nikita-volkov/lawful-conversions.git
+
+common language-settings
+  default-language: Haskell2010
+  default-extensions:
+    BlockArguments
+    DefaultSignatures
+    FlexibleContexts
+    FlexibleInstances
+    MagicHash
+    MultiParamTypeClasses
+    NoImplicitPrelude
+    ScopedTypeVariables
+    TypeApplications
+    UndecidableSuperClasses
+
+library
+  import: language-settings
+  hs-source-dirs: src/library
+  exposed-modules: LawfulConversions
+  other-modules:
+    LawfulConversions.Classes
+    LawfulConversions.Classes.Is
+    LawfulConversions.Classes.IsMany
+    LawfulConversions.Classes.IsSome
+    LawfulConversions.Optics
+    LawfulConversions.Prelude
+    LawfulConversions.Properties
+    LawfulConversions.Proxies
+    LawfulConversions.Proxies.ViaIsSome
+    LawfulConversions.Relations
+    LawfulConversions.Relations.BoxedVectorAndList
+    LawfulConversions.Relations.BoxedVectorAndSeq
+    LawfulConversions.Relations.ByteArrayAndByteString
+    LawfulConversions.Relations.ByteArrayAndLazyByteString
+    LawfulConversions.Relations.ByteArrayAndLazyByteStringBuilder
+    LawfulConversions.Relations.ByteArrayAndShortByteString
+    LawfulConversions.Relations.ByteArrayAndTextArray
+    LawfulConversions.Relations.ByteArrayAndWord8List
+    LawfulConversions.Relations.ByteStringAndLazyByteString
+    LawfulConversions.Relations.ByteStringAndLazyByteStringBuilder
+    LawfulConversions.Relations.ByteStringAndShortByteString
+    LawfulConversions.Relations.ByteStringAndText
+    LawfulConversions.Relations.ByteStringAndTextArray
+    LawfulConversions.Relations.ByteStringAndWord8List
+    LawfulConversions.Relations.Int16AndWord16
+    LawfulConversions.Relations.Int32AndWord32
+    LawfulConversions.Relations.Int64AndWord64
+    LawfulConversions.Relations.Int8AndWord8
+    LawfulConversions.Relations.IntAndWord
+    LawfulConversions.Relations.IntMapAndMapOfInt
+    LawfulConversions.Relations.IntSetAndSetOfInt
+    LawfulConversions.Relations.LazyByteStringAndLazyByteStringBuilder
+    LawfulConversions.Relations.LazyByteStringAndLazyText
+    LawfulConversions.Relations.LazyByteStringAndShortByteString
+    LawfulConversions.Relations.LazyByteStringAndTextArray
+    LawfulConversions.Relations.LazyByteStringAndWord8List
+    LawfulConversions.Relations.LazyByteStringBuilderAndShortByteString
+    LawfulConversions.Relations.LazyByteStringBuilderAndTextArray
+    LawfulConversions.Relations.LazyByteStringBuilderAndWord8List
+    LawfulConversions.Relations.LazyTextAndLazyTextBuilder
+    LawfulConversions.Relations.LazyTextAndStrictTextBuilder
+    LawfulConversions.Relations.LazyTextAndString
+    LawfulConversions.Relations.LazyTextAndText
+    LawfulConversions.Relations.LazyTextBuilderAndStrictTextBuilder
+    LawfulConversions.Relations.LazyTextBuilderAndString
+    LawfulConversions.Relations.LazyTextBuilderAndText
+    LawfulConversions.Relations.ListAndSeq
+    LawfulConversions.Relations.ShortByteStringAndTextArray
+    LawfulConversions.Relations.ShortByteStringAndWord8List
+    LawfulConversions.Relations.StrictTextBuilderAndString
+    LawfulConversions.Relations.StrictTextBuilderAndText
+    LawfulConversions.Relations.StringAndText
+    LawfulConversions.Relations.TextArrayAndWord8List
+    LawfulConversions.TextCompat.Array
+
+  build-depends:
+    QuickCheck >=2.13 && <3,
+    base >=4.12 && <5,
+    bytestring >=0.10 && <0.13,
+    containers >=0.6 && <0.8,
+    hashable >=1 && <2,
+    primitive >=0.7 && <0.10,
+    profunctors >=5 && <6,
+    text >=1.2 && <2.2,
+    unordered-containers >=0.2 && <0.3,
+    vector >=0.12 && <0.14,
+
+test-suite test
+  import: language-settings
+  type: exitcode-stdio-1.0
+  hs-source-dirs: src/test
+  main-is: Main.hs
+  other-modules: Test.ExtraInstances
+  build-depends:
+    QuickCheck >=2.13 && <3,
+    bytestring >=0.11.1.0 && <0.13,
+    lawful-conversions,
+    primitive >=0.7 && <0.10,
+    quickcheck-instances >=0.3.32 && <0.4,
+    rebase >=1.15 && <2,
+    tasty >=1.2.3 && <2,
+    tasty-quickcheck >=0.10.1 && <0.11,
+    text >=1.2 && <3,
diff --git a/src/library/LawfulConversions.hs b/src/library/LawfulConversions.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions.hs
@@ -0,0 +1,111 @@
+-- |
+-- 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
+-- perform a conversion between two types. The main difference between them
+-- is in what the first type application parameter specifies. E.g.:
+--
+-- > toString = to @String
+--
+-- > fromText = from @Text
+--
+-- The types should be self-evident:
+--
+-- > > :t to @String
+-- > to @String :: IsSome String b => b -> String
+--
+-- > > :t from @Text
+-- > from @Text :: IsMany Text b => Text -> b
+--
+-- In other words 'to' and 'from' let you explicitly specify either the source
+-- or the target type of a conversion when you need to help the type
+-- inferencer or the reader.
+--
+-- == Examples
+--
+-- @
+-- renderNameAndHeight :: 'Text' -> 'Int' -> 'Text'
+-- renderNameAndHeight name height =
+--   'from' @'Data.Text.Encoding.StrictTextBuilder' $
+--     "Height of " <> 'to' name <> " is " <> 'to' (show height)
+-- @
+--
+-- @
+-- combineEncodings :: 'Data.ByteString.Short.ShortByteString' -> 'Data.Primitive.ByteArray' -> ['Word8'] -> 'Data.ByteString.Lazy.ByteString'
+-- combineEncodings a b c =
+--   'from' @'Data.ByteString.Builder.Builder' $
+--     'to' a <> 'to' b <> 'to' c
+-- @
+--
+-- = Partial conversions
+--
+-- This library also captures the pattern of smart constructors via the 'IsSome' class, which associates a total 'to' conversion with its partial inverse 'maybeFrom'.
+--
+-- This captures the codec relationship between types.
+-- E.g.,
+--
+-- - Every 'Int16' can be losslessly converted into 'Int32', but not every 'Int32' can be losslessly converted into 'Int16'.
+--
+-- - 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.
+module LawfulConversions
+  ( -- * Typeclasses
+    IsSome (..),
+    IsMany (..),
+    Is,
+
+    -- * Optics
+    isSomePrism,
+    isManyIso,
+    isIso,
+
+    -- * Instance derivation
+
+    -- | Proxy data-types useful for deriving various standard instances using the @DerivingVia@ extension.
+    module LawfulConversions.Proxies,
+
+    -- * Testing
+    module LawfulConversions.Properties,
+  )
+where
+
+import LawfulConversions.Classes
+import LawfulConversions.Optics
+import LawfulConversions.Properties
+import LawfulConversions.Proxies
+import LawfulConversions.Relations ()
diff --git a/src/library/LawfulConversions/Classes.hs b/src/library/LawfulConversions/Classes.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Classes.hs
@@ -0,0 +1,5 @@
+module LawfulConversions.Classes (module Exports) where
+
+import LawfulConversions.Classes.Is as Exports
+import LawfulConversions.Classes.IsMany as Exports
+import LawfulConversions.Classes.IsSome as Exports
diff --git a/src/library/LawfulConversions/Classes/Is.hs b/src/library/LawfulConversions/Classes/Is.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Classes/Is.hs
@@ -0,0 +1,36 @@
+module LawfulConversions.Classes.Is where
+
+import LawfulConversions.Classes.IsMany
+
+-- | Bidirectional conversion between two types with no loss of information.
+--
+-- The bidirectionality is encoded via a recursive dependency with arguments
+-- flipped.
+--
+-- You can read the signature @Is a b@ as \"/B/ is /A/\".
+--
+-- === 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' . '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.
+--
+-- - @'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.
+--
+-- === 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@.
+class (IsMany a b, Is b a) => Is a b
+
+-- | Any type is isomorphic to itself.
+instance Is a a
diff --git a/src/library/LawfulConversions/Classes/IsMany.hs b/src/library/LawfulConversions/Classes/IsMany.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Classes/IsMany.hs
@@ -0,0 +1,44 @@
+module LawfulConversions.Classes.IsMany where
+
+import LawfulConversions.Classes.IsSome
+
+-- |
+-- Lossy or canonicalizing conversion.
+-- Captures mappings from multiple alternative inputs into one output.
+--
+-- E.g.,
+--
+-- - `ByteString` can be decoded into `Text` with UTF-8 leniently, replacing the invalid chars with a default char.
+--
+-- - `String` has a wider range of supported chars than `Text`, so some chars get replaced too.
+--
+-- === Laws
+--
+-- ==== 'from' is an inverse of 'to'
+--
+-- > \sup -> sup == from (to sup)
+--
+-- === Testing
+--
+-- For testing whether your instances conform to these laws use 'LawfulConversions.isManyProperties'.
+class (IsSome sup sub) => IsMany sup sub where
+  -- |
+  -- Possibly lossy inverse of 'to'.
+  -- [Surjection](https://en.wikipedia.org/wiki/Surjective_function) from @sup@ to @sub@.
+  --
+  -- 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 = from @Text
+  --
+  -- The first type application of the 'to' function on the other hand specifies
+  -- the output data type.
+  from :: sup -> sub
+
+  -- |
+  -- Requires the presence of 'IsSome' in reverse direction.
+  default from :: (IsSome sub sup) => sup -> sub
+  from = to
+
+instance IsMany sup sup
diff --git a/src/library/LawfulConversions/Classes/IsSome.hs b/src/library/LawfulConversions/Classes/IsSome.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Classes/IsSome.hs
@@ -0,0 +1,53 @@
+module LawfulConversions.Classes.IsSome where
+
+import LawfulConversions.Prelude
+
+-- |
+-- Evidence that all values of type @sub@ form a subset of all values of type @sup@.
+--
+-- [From Wikipedia](https://en.wikipedia.org/wiki/Subset):
+--
+-- In mathematics, a set A is a subset of a set B if all elements of A are also elements of B; B is then a superset of A. It is possible for A and B to be equal; if they are unequal, then A is a proper subset of B. The relationship of one set being a subset of another is called inclusion (or sometimes containment). A is a subset of B may also be expressed as B includes (or contains) A or A is included (or contained) in B. A k-subset is a subset with k elements.
+--
+-- === Laws
+--
+-- ==== 'to' is injective
+--
+-- For every two values of type @sub@ that are not equal converting with 'to' will always produce values that are not equal.
+--
+-- > \(a, b) -> a == b || to a /= to b
+--
+-- ==== 'maybeFrom' is an inverse 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.
+--
+-- > \a -> maybeFrom (to a) == Just a
+--
+-- === Testing
+--
+-- For testing whether your instances conform to these laws use 'LawfulConversions.isSomeProperties'.
+class IsSome sup sub where
+  -- |
+  -- Convert a value of a subset type to a superset type.
+  --
+  -- This function is injective non-surjective.
+  to :: sub -> sup
+
+  -- |
+  -- [Partial inverse](https://en.wikipedia.org/wiki/Inverse_function#Partial_inverses) of 'to'.
+  maybeFrom :: sup -> Maybe sub
+
+  -- |
+  -- Requires the presence of 'IsSome' in reverse direction.
+  default maybeFrom :: (IsSome sub sup) => sup -> Maybe sub
+  maybeFrom = Just . to
+
+-- | Every type is isomorphic to itself.
+instance IsSome a a where
+  to = id
+  maybeFrom = Just . id
+
+-- | The empty set has no elements, and therefore is vacuously a subset of any set.
+instance IsSome sup Void where
+  to = absurd
+  maybeFrom = const Nothing
diff --git a/src/library/LawfulConversions/Optics.hs b/src/library/LawfulConversions/Optics.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Optics.hs
@@ -0,0 +1,21 @@
+module LawfulConversions.Optics where
+
+import Data.Profunctor
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+-- | Van-Laarhoven-style Prism, compatible with the \"lens\" library.
+isSomePrism :: (IsSome a b, Choice p, Applicative f) => p b (f b) -> p a (f a)
+isSomePrism =
+  dimap
+    (\s -> maybe (Left s) Right (maybeFrom s))
+    (either pure (fmap to))
+    . right'
+
+-- | Van-Laarhoven-style Isomorphism, compatible with the \"lens\" library.
+isManyIso :: (IsMany a b, Profunctor p, Functor f) => p b (f b) -> p a (f a)
+isManyIso = dimap from (fmap to)
+
+-- | Van-Laarhoven-style Isomorphism, compatible with the \"lens\" library.
+isIso :: (Is a b, Profunctor p, Functor f) => p b (f b) -> p a (f a)
+isIso = isManyIso
diff --git a/src/library/LawfulConversions/Prelude.hs b/src/library/LawfulConversions/Prelude.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Prelude.hs
@@ -0,0 +1,89 @@
+module LawfulConversions.Prelude
+  ( module Exports,
+    as,
+  )
+where
+
+import Control.Applicative as Exports
+import Control.Category as Exports
+import Control.Concurrent as Exports
+import Control.Exception as Exports
+import Control.Monad as Exports hiding (fail, forM, forM_, mapM, mapM_, msum, sequence, sequence_)
+import Control.Monad.Fail as Exports
+import Control.Monad.Fix as Exports hiding (fix)
+import Control.Monad.IO.Class as Exports
+import Control.Monad.ST as Exports
+import Data.Bifunctor as Exports
+import Data.Bits as Exports
+import Data.Bool as Exports
+import Data.ByteString as Exports (ByteString)
+import Data.Char as Exports
+import Data.Coerce as Exports
+import Data.Complex as Exports
+import Data.Data as Exports
+import Data.Dynamic as Exports
+import Data.Either as Exports
+import Data.Fixed as Exports
+import Data.Foldable as Exports hiding (toList)
+import Data.Function as Exports hiding (id, (.))
+import Data.Functor as Exports hiding (unzip)
+import Data.Functor.Classes as Exports
+import Data.Functor.Compose as Exports
+import Data.Functor.Contravariant as Exports
+import Data.Functor.Identity as Exports
+import Data.HashMap.Strict as Exports (HashMap)
+import Data.HashSet as Exports (HashSet)
+import Data.Hashable as Exports
+import Data.IORef as Exports
+import Data.Int as Exports
+import Data.IntMap.Strict as Exports (IntMap)
+import Data.IntSet as Exports (IntSet)
+import Data.Ix as Exports
+import Data.List as Exports hiding (all, and, any, concat, concatMap, elem, find, foldl, foldl', foldl1, foldr, foldr1, mapAccumL, mapAccumR, maximum, maximumBy, minimum, minimumBy, notElem, or, product, sum)
+import Data.List.NonEmpty as Exports (NonEmpty (..))
+import Data.Map.Strict as Exports (Map)
+import Data.Maybe as Exports
+import Data.Monoid as Exports hiding (First (..), Last (..), (<>))
+import Data.Ord as Exports
+import Data.Proxy as Exports
+import Data.Ratio as Exports
+import Data.STRef as Exports
+import Data.Semigroup as Exports
+import Data.Sequence as Exports (Seq)
+import Data.Set as Exports (Set)
+import Data.String as Exports
+import Data.Text as Exports (Text)
+import Data.Traversable as Exports
+import Data.Tuple as Exports
+import Data.Vector as Exports (Vector)
+import Data.Version as Exports
+import Data.Void as Exports
+import Data.Word as Exports
+import Debug.Trace as Exports
+import Foreign.ForeignPtr as Exports
+import Foreign.Ptr as Exports
+import Foreign.StablePtr as Exports
+import Foreign.Storable as Exports
+import GHC.Conc as Exports hiding (orElse, threadWaitRead, threadWaitReadSTM, threadWaitWrite, threadWaitWriteSTM, withMVar)
+import GHC.Exts as Exports (IsList (..), groupWith, inline, lazy, sortWith)
+import GHC.Generics as Exports (Generic, Generic1)
+import GHC.IO.Exception as Exports
+import GHC.OverloadedLabels as Exports
+import GHC.Records as Exports
+import Numeric as Exports
+import Numeric.Natural as Exports
+import System.Environment as Exports
+import System.Exit as Exports
+import System.IO as Exports
+import System.IO.Error as Exports
+import System.IO.Unsafe as Exports
+import System.Mem as Exports
+import System.Mem.StableName as Exports
+import System.Timeout as Exports
+import Text.Printf as Exports (hPrintf, printf)
+import Text.Read as Exports (Read (..), readEither, readMaybe)
+import Unsafe.Coerce as Exports
+import Prelude as Exports hiding (all, and, any, concat, concatMap, elem, fail, foldl, foldl1, foldr, foldr1, id, mapM, mapM_, maximum, minimum, notElem, or, product, sequence, sequence_, sum, (.))
+
+as :: proxy c -> c -> c
+as = flip asProxyTypeOf
diff --git a/src/library/LawfulConversions/Properties.hs b/src/library/LawfulConversions/Properties.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Properties.hs
@@ -0,0 +1,94 @@
+module LawfulConversions.Properties
+  ( isSomeProperties,
+    isManyProperties,
+    isProperties,
+  )
+where
+
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import Test.QuickCheck
+
+-- |
+-- Properties testing whether an instance satisfies the laws of 'IsSome'.
+--
+-- The instance is identified via the proxy types that you provide.
+--
+-- E.g., here's how you can integrate it into an Hspec test-suite:
+--
+-- > spec = do
+-- >   describe "IsSome laws" do
+-- >     traverse_
+-- >       (uncurry prop)
+-- >       (isSomeProperties @Int32 @Int16 Proxy Proxy)
+isSomeProperties ::
+  (IsSome a b, Eq a, Eq b, Show a, Show b, Arbitrary b) =>
+  Proxy a ->
+  Proxy b ->
+  [(String, Property)]
+isSomeProperties aProxy bProxy =
+  [ ( "'to' is injective",
+      property \a b ->
+        a /= b ==>
+          to' a =/= to' b
+    ),
+    ( "'maybeFrom' is an inverse of 'to'",
+      property \a ->
+        maybeFrom' (to' a) === Just a
+    )
+  ]
+  where
+    to' = as aProxy . to . as bProxy
+    maybeFrom' = fmap (as bProxy) . maybeFrom . as aProxy
+
+-- |
+-- Properties testing whether an instance satisfies the laws of 'IsMany'.
+--
+-- The instance is identified via the proxy types that you provide.
+--
+-- E.g., here's how you can integrate it into an Hspec test-suite:
+--
+-- > spec = do
+-- >   describe "IsMany laws" do
+-- >     traverse_
+-- >       (uncurry prop)
+-- >       (isManyProperties @String @Text Proxy Proxy)
+isManyProperties ::
+  (IsMany a b, Eq a, Eq b, Show a, Show b, Arbitrary b) =>
+  Proxy a ->
+  Proxy b ->
+  [(String, Property)]
+isManyProperties aProxy bProxy =
+  ( "'from' is an inverse of 'to'",
+    property \b -> b === from' (to' b)
+  )
+    : isSomeProperties aProxy bProxy
+  where
+    to' = as aProxy . to . as bProxy
+    from' = as bProxy . from . as aProxy
+
+-- |
+-- Properties testing whether an instance satisfies the laws of 'Is'.
+--
+-- The instance is identified via the proxy types that you provide.
+--
+-- E.g., here's how you can integrate it into an Hspec test-suite:
+--
+-- > spec = do
+-- >   describe "Is laws" do
+-- >     traverse_
+-- >       (uncurry prop)
+-- >       (isProperties @Int32 @Word32 Proxy Proxy)
+isProperties ::
+  (Is a b, Eq a, Eq b, Show a, Show b, Arbitrary a, Arbitrary b) =>
+  Proxy a ->
+  Proxy b ->
+  [(String, Property)]
+isProperties aProxy bProxy =
+  ( "'to' is an inverse of 'from'",
+    property \b -> b === to' (from' b)
+  )
+    : isManyProperties aProxy bProxy
+  where
+    to' = as aProxy . to . as bProxy
+    from' = as bProxy . from . as aProxy
diff --git a/src/library/LawfulConversions/Proxies.hs b/src/library/LawfulConversions/Proxies.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Proxies.hs
@@ -0,0 +1,3 @@
+module LawfulConversions.Proxies (module Exports) where
+
+import LawfulConversions.Proxies.ViaIsSome as Exports
diff --git a/src/library/LawfulConversions/Proxies/ViaIsSome.hs b/src/library/LawfulConversions/Proxies/ViaIsSome.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Proxies/ViaIsSome.hs
@@ -0,0 +1,72 @@
+module LawfulConversions.Proxies.ViaIsSome where
+
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import qualified Test.QuickCheck as QuickCheck
+
+-- |
+-- Helper for deriving common instances on types which have an instance of @'IsSome' sup@ using the @DerivingVia@ extension.
+--
+-- E.g.,
+--
+-- > newtype Percent = Percent Double
+-- >   deriving newtype (Show, Eq, Ord)
+-- >   deriving (Read, Arbitrary) via (ViaIsSome Double Percent)
+-- >
+-- > instance IsSome Double Percent where
+-- >   to (Percent double) = double
+-- >   maybeFrom double =
+-- >     if double < 0 || double > 1
+-- >       then Nothing
+-- >       else Just (Percent double)
+--
+-- 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
+
+instance (IsSome sup sub) => IsSome sup (ViaIsSome sup sub) where
+  to (ViaIsSome a) = to a
+  maybeFrom = fmap ViaIsSome . maybeFrom
+
+instance IsSome sub (ViaIsSome sup sub) where
+  to = coerce
+
+instance IsSome (ViaIsSome sup sub) sub where
+  to = coerce
+
+instance IsMany sub (ViaIsSome sup sub)
+
+instance IsMany (ViaIsSome sup sub) sub
+
+instance Is sub (ViaIsSome sup sub)
+
+instance Is (ViaIsSome sup sub) sub
+
+instance (IsSome sup sub, Show sup) => Show (ViaIsSome sup sub) where
+  show (ViaIsSome a) = show (to @sup a)
+
+instance (IsSome sup sub, Read sup) => Read (ViaIsSome sup sub) where
+  readPrec = do
+    sup <- readPrec
+    case maybeFrom @sup sup 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
+  fromString =
+    maybe (error "Value is not from the subset") ViaIsSome . maybeFrom @sup . fromString
+
+instance (IsSome sup sub, Eq sup) => Eq (ViaIsSome sup sub) where
+  (==) = on (==) (to @sup)
+
+instance (IsSome sup sub, Ord sup) => Ord (ViaIsSome sup sub) where
+  compare = on compare (to @sup)
+
+instance (IsSome sup sub, QuickCheck.Arbitrary sup) => QuickCheck.Arbitrary (ViaIsSome sup sub) where
+  arbitrary =
+    QuickCheck.suchThatMap QuickCheck.arbitrary (maybeFrom @sup)
+  shrink value = do
+    shrunkValue <- QuickCheck.shrink (to @sup value)
+    shrunkValue
+      & maybeFrom
+      & maybeToList
diff --git a/src/library/LawfulConversions/Relations.hs b/src/library/LawfulConversions/Relations.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations.hs
@@ -0,0 +1,45 @@
+module LawfulConversions.Relations () where
+
+import LawfulConversions.Relations.BoxedVectorAndList ()
+import LawfulConversions.Relations.BoxedVectorAndSeq ()
+import LawfulConversions.Relations.ByteArrayAndByteString ()
+import LawfulConversions.Relations.ByteArrayAndLazyByteString ()
+import LawfulConversions.Relations.ByteArrayAndLazyByteStringBuilder ()
+import LawfulConversions.Relations.ByteArrayAndShortByteString ()
+import LawfulConversions.Relations.ByteArrayAndTextArray ()
+import LawfulConversions.Relations.ByteArrayAndWord8List ()
+import LawfulConversions.Relations.ByteStringAndLazyByteString ()
+import LawfulConversions.Relations.ByteStringAndLazyByteStringBuilder ()
+import LawfulConversions.Relations.ByteStringAndShortByteString ()
+import LawfulConversions.Relations.ByteStringAndText ()
+import LawfulConversions.Relations.ByteStringAndTextArray ()
+import LawfulConversions.Relations.ByteStringAndWord8List ()
+import LawfulConversions.Relations.Int16AndWord16 ()
+import LawfulConversions.Relations.Int32AndWord32 ()
+import LawfulConversions.Relations.Int64AndWord64 ()
+import LawfulConversions.Relations.Int8AndWord8 ()
+import LawfulConversions.Relations.IntAndWord ()
+import LawfulConversions.Relations.IntMapAndMapOfInt ()
+import LawfulConversions.Relations.IntSetAndSetOfInt ()
+import LawfulConversions.Relations.LazyByteStringAndLazyByteStringBuilder ()
+import LawfulConversions.Relations.LazyByteStringAndLazyText ()
+import LawfulConversions.Relations.LazyByteStringAndShortByteString ()
+import LawfulConversions.Relations.LazyByteStringAndTextArray ()
+import LawfulConversions.Relations.LazyByteStringAndWord8List ()
+import LawfulConversions.Relations.LazyByteStringBuilderAndShortByteString ()
+import LawfulConversions.Relations.LazyByteStringBuilderAndTextArray ()
+import LawfulConversions.Relations.LazyByteStringBuilderAndWord8List ()
+import LawfulConversions.Relations.LazyTextAndLazyTextBuilder ()
+import LawfulConversions.Relations.LazyTextAndStrictTextBuilder ()
+import LawfulConversions.Relations.LazyTextAndString ()
+import LawfulConversions.Relations.LazyTextAndText ()
+import LawfulConversions.Relations.LazyTextBuilderAndStrictTextBuilder ()
+import LawfulConversions.Relations.LazyTextBuilderAndString ()
+import LawfulConversions.Relations.LazyTextBuilderAndText ()
+import LawfulConversions.Relations.ListAndSeq ()
+import LawfulConversions.Relations.ShortByteStringAndTextArray ()
+import LawfulConversions.Relations.ShortByteStringAndWord8List ()
+import LawfulConversions.Relations.StrictTextBuilderAndString ()
+import LawfulConversions.Relations.StrictTextBuilderAndText ()
+import LawfulConversions.Relations.StringAndText ()
+import LawfulConversions.Relations.TextArrayAndWord8List ()
diff --git a/src/library/LawfulConversions/Relations/BoxedVectorAndList.hs b/src/library/LawfulConversions/Relations/BoxedVectorAndList.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/BoxedVectorAndList.hs
@@ -0,0 +1,21 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.BoxedVectorAndList where
+
+import qualified Data.Vector
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome (Vector a) [a] where
+  to = Data.Vector.fromList
+
+instance IsSome [a] (Vector a) where
+  to = Data.Vector.toList
+
+instance IsMany (Vector a) [a]
+
+instance IsMany [a] (Vector a)
+
+instance Is (Vector a) [a]
+
+instance Is [a] (Vector a)
diff --git a/src/library/LawfulConversions/Relations/BoxedVectorAndSeq.hs b/src/library/LawfulConversions/Relations/BoxedVectorAndSeq.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/BoxedVectorAndSeq.hs
@@ -0,0 +1,22 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.BoxedVectorAndSeq where
+
+import qualified Data.Sequence
+import qualified Data.Vector
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome (Vector a) (Seq a) where
+  to = Data.Vector.fromList . toList
+
+instance IsSome (Seq a) (Vector a) where
+  to = Data.Sequence.fromList . Data.Vector.toList
+
+instance IsMany (Vector a) (Seq a)
+
+instance IsMany (Seq a) (Vector a)
+
+instance Is (Vector a) (Seq a)
+
+instance Is (Seq a) (Vector a)
diff --git a/src/library/LawfulConversions/Relations/ByteArrayAndByteString.hs b/src/library/LawfulConversions/Relations/ByteArrayAndByteString.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ByteArrayAndByteString.hs
@@ -0,0 +1,24 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ByteArrayAndByteString where
+
+import qualified Data.ByteString.Short
+import qualified Data.Primitive.ByteArray
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import LawfulConversions.Relations.ByteArrayAndShortByteString ()
+import LawfulConversions.Relations.ByteStringAndShortByteString ()
+
+instance IsSome Data.Primitive.ByteArray.ByteArray ByteString where
+  to = to . to @Data.ByteString.Short.ShortByteString
+
+instance IsSome ByteString Data.Primitive.ByteArray.ByteArray where
+  to = to . to @Data.ByteString.Short.ShortByteString
+
+instance IsMany Data.Primitive.ByteArray.ByteArray ByteString
+
+instance IsMany ByteString Data.Primitive.ByteArray.ByteArray
+
+instance Is Data.Primitive.ByteArray.ByteArray ByteString
+
+instance Is ByteString Data.Primitive.ByteArray.ByteArray
diff --git a/src/library/LawfulConversions/Relations/ByteArrayAndLazyByteString.hs b/src/library/LawfulConversions/Relations/ByteArrayAndLazyByteString.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ByteArrayAndLazyByteString.hs
@@ -0,0 +1,25 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ByteArrayAndLazyByteString where
+
+import qualified Data.ByteString.Lazy
+import qualified Data.ByteString.Short
+import qualified Data.Primitive.ByteArray
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import LawfulConversions.Relations.ByteArrayAndShortByteString ()
+import LawfulConversions.Relations.LazyByteStringAndShortByteString ()
+
+instance IsSome Data.ByteString.Lazy.ByteString Data.Primitive.ByteArray.ByteArray where
+  to = to . to @Data.ByteString.Short.ShortByteString
+
+instance IsSome Data.Primitive.ByteArray.ByteArray Data.ByteString.Lazy.ByteString where
+  to = to . to @Data.ByteString.Short.ShortByteString
+
+instance IsMany Data.Primitive.ByteArray.ByteArray Data.ByteString.Lazy.ByteString
+
+instance IsMany Data.ByteString.Lazy.ByteString Data.Primitive.ByteArray.ByteArray
+
+instance Is Data.Primitive.ByteArray.ByteArray Data.ByteString.Lazy.ByteString
+
+instance Is Data.ByteString.Lazy.ByteString Data.Primitive.ByteArray.ByteArray
diff --git a/src/library/LawfulConversions/Relations/ByteArrayAndLazyByteStringBuilder.hs b/src/library/LawfulConversions/Relations/ByteArrayAndLazyByteStringBuilder.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ByteArrayAndLazyByteStringBuilder.hs
@@ -0,0 +1,25 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ByteArrayAndLazyByteStringBuilder where
+
+import qualified Data.ByteString.Builder
+import qualified Data.ByteString.Short
+import qualified Data.Primitive.ByteArray
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import LawfulConversions.Relations.ByteArrayAndShortByteString ()
+import LawfulConversions.Relations.LazyByteStringBuilderAndShortByteString ()
+
+instance IsSome Data.Primitive.ByteArray.ByteArray Data.ByteString.Builder.Builder where
+  to = to . to @Data.ByteString.Short.ShortByteString
+
+instance IsSome Data.ByteString.Builder.Builder Data.Primitive.ByteArray.ByteArray where
+  to = to . to @Data.ByteString.Short.ShortByteString
+
+instance IsMany Data.Primitive.ByteArray.ByteArray Data.ByteString.Builder.Builder
+
+instance IsMany Data.ByteString.Builder.Builder Data.Primitive.ByteArray.ByteArray
+
+instance Is Data.Primitive.ByteArray.ByteArray Data.ByteString.Builder.Builder
+
+instance Is Data.ByteString.Builder.Builder Data.Primitive.ByteArray.ByteArray
diff --git a/src/library/LawfulConversions/Relations/ByteArrayAndShortByteString.hs b/src/library/LawfulConversions/Relations/ByteArrayAndShortByteString.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ByteArrayAndShortByteString.hs
@@ -0,0 +1,24 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ByteArrayAndShortByteString where
+
+import qualified Data.ByteString.Short
+import qualified Data.ByteString.Short.Internal
+import qualified Data.Primitive.ByteArray
+import LawfulConversions.Classes
+
+instance IsSome Data.ByteString.Short.ShortByteString Data.Primitive.ByteArray.ByteArray where
+  to (Data.Primitive.ByteArray.ByteArray array) =
+    Data.ByteString.Short.Internal.SBS array
+
+instance IsSome Data.Primitive.ByteArray.ByteArray Data.ByteString.Short.ShortByteString where
+  to (Data.ByteString.Short.Internal.SBS array) =
+    Data.Primitive.ByteArray.ByteArray array
+
+instance IsMany Data.Primitive.ByteArray.ByteArray Data.ByteString.Short.ShortByteString
+
+instance IsMany Data.ByteString.Short.ShortByteString Data.Primitive.ByteArray.ByteArray
+
+instance Is Data.Primitive.ByteArray.ByteArray Data.ByteString.Short.ShortByteString
+
+instance Is Data.ByteString.Short.ShortByteString Data.Primitive.ByteArray.ByteArray
diff --git a/src/library/LawfulConversions/Relations/ByteArrayAndTextArray.hs b/src/library/LawfulConversions/Relations/ByteArrayAndTextArray.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ByteArrayAndTextArray.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ByteArrayAndTextArray where
+
+#if !MIN_VERSION_text(2,1,0)
+
+import qualified Data.Primitive.ByteArray
+import qualified Data.Text.Array
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import qualified LawfulConversions.TextCompat.Array
+
+instance IsSome Data.Primitive.ByteArray.ByteArray Data.Text.Array.Array where
+  to = LawfulConversions.TextCompat.Array.toByteArray
+
+instance IsSome Data.Text.Array.Array Data.Primitive.ByteArray.ByteArray where
+  to = LawfulConversions.TextCompat.Array.fromByteArray
+
+instance IsMany Data.Primitive.ByteArray.ByteArray Data.Text.Array.Array
+
+instance IsMany Data.Text.Array.Array Data.Primitive.ByteArray.ByteArray
+
+instance Is Data.Primitive.ByteArray.ByteArray Data.Text.Array.Array
+
+instance Is Data.Text.Array.Array Data.Primitive.ByteArray.ByteArray
+
+#endif
diff --git a/src/library/LawfulConversions/Relations/ByteArrayAndWord8List.hs b/src/library/LawfulConversions/Relations/ByteArrayAndWord8List.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ByteArrayAndWord8List.hs
@@ -0,0 +1,22 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ByteArrayAndWord8List where
+
+import qualified Data.Primitive.ByteArray
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import LawfulConversions.Relations.ByteArrayAndShortByteString ()
+
+instance IsSome Data.Primitive.ByteArray.ByteArray [Word8] where
+  to = fromList
+
+instance IsSome [Word8] Data.Primitive.ByteArray.ByteArray where
+  to = toList
+
+instance IsMany Data.Primitive.ByteArray.ByteArray [Word8]
+
+instance IsMany [Word8] Data.Primitive.ByteArray.ByteArray
+
+instance Is Data.Primitive.ByteArray.ByteArray [Word8]
+
+instance Is [Word8] Data.Primitive.ByteArray.ByteArray
diff --git a/src/library/LawfulConversions/Relations/ByteStringAndLazyByteString.hs b/src/library/LawfulConversions/Relations/ByteStringAndLazyByteString.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ByteStringAndLazyByteString.hs
@@ -0,0 +1,21 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ByteStringAndLazyByteString where
+
+import qualified Data.ByteString.Lazy
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome ByteString Data.ByteString.Lazy.ByteString where
+  to = Data.ByteString.Lazy.toStrict
+
+instance IsSome Data.ByteString.Lazy.ByteString ByteString where
+  to = Data.ByteString.Lazy.fromStrict
+
+instance IsMany ByteString Data.ByteString.Lazy.ByteString
+
+instance IsMany Data.ByteString.Lazy.ByteString ByteString
+
+instance Is ByteString Data.ByteString.Lazy.ByteString
+
+instance Is Data.ByteString.Lazy.ByteString ByteString
diff --git a/src/library/LawfulConversions/Relations/ByteStringAndLazyByteStringBuilder.hs b/src/library/LawfulConversions/Relations/ByteStringAndLazyByteStringBuilder.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ByteStringAndLazyByteStringBuilder.hs
@@ -0,0 +1,22 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ByteStringAndLazyByteStringBuilder where
+
+import qualified Data.ByteString.Builder
+import qualified Data.ByteString.Lazy
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome ByteString Data.ByteString.Builder.Builder where
+  to = Data.ByteString.Lazy.toStrict . Data.ByteString.Builder.toLazyByteString
+
+instance IsSome Data.ByteString.Builder.Builder ByteString where
+  to = Data.ByteString.Builder.byteString
+
+instance IsMany Data.ByteString.Builder.Builder ByteString
+
+instance IsMany ByteString Data.ByteString.Builder.Builder
+
+instance Is Data.ByteString.Builder.Builder ByteString
+
+instance Is ByteString Data.ByteString.Builder.Builder
diff --git a/src/library/LawfulConversions/Relations/ByteStringAndShortByteString.hs b/src/library/LawfulConversions/Relations/ByteStringAndShortByteString.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ByteStringAndShortByteString.hs
@@ -0,0 +1,21 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ByteStringAndShortByteString where
+
+import qualified Data.ByteString.Short
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome ByteString Data.ByteString.Short.ShortByteString where
+  to = Data.ByteString.Short.fromShort
+
+instance IsSome Data.ByteString.Short.ShortByteString ByteString where
+  to = Data.ByteString.Short.toShort
+
+instance IsMany ByteString Data.ByteString.Short.ShortByteString
+
+instance IsMany Data.ByteString.Short.ShortByteString ByteString
+
+instance Is ByteString Data.ByteString.Short.ShortByteString
+
+instance Is Data.ByteString.Short.ShortByteString ByteString
diff --git a/src/library/LawfulConversions/Relations/ByteStringAndText.hs b/src/library/LawfulConversions/Relations/ByteStringAndText.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ByteStringAndText.hs
@@ -0,0 +1,17 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ByteStringAndText where
+
+import qualified Data.Text.Encoding
+import qualified Data.Text.Encoding.Error
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+-- | UTF-8 codec.
+instance IsSome ByteString Text where
+  to = Data.Text.Encoding.encodeUtf8
+  maybeFrom = either (const Nothing) Just . Data.Text.Encoding.decodeUtf8'
+
+-- | Lenient UTF-8 decoding.
+instance IsMany ByteString Text where
+  from = Data.Text.Encoding.decodeUtf8With Data.Text.Encoding.Error.lenientDecode
diff --git a/src/library/LawfulConversions/Relations/ByteStringAndTextArray.hs b/src/library/LawfulConversions/Relations/ByteStringAndTextArray.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ByteStringAndTextArray.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ByteStringAndTextArray where
+
+#if !MIN_VERSION_text(2,1,0)
+
+import qualified Data.ByteString.Short
+import qualified Data.Text.Array
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import qualified LawfulConversions.TextCompat.Array
+
+instance IsSome ByteString Data.Text.Array.Array where
+  to = Data.ByteString.Short.fromShort . LawfulConversions.TextCompat.Array.toShortByteString
+
+instance IsSome Data.Text.Array.Array ByteString where
+  to = LawfulConversions.TextCompat.Array.fromShortByteString . Data.ByteString.Short.toShort
+
+instance IsMany ByteString Data.Text.Array.Array
+
+instance IsMany Data.Text.Array.Array ByteString
+
+instance Is ByteString Data.Text.Array.Array
+
+instance Is Data.Text.Array.Array ByteString
+
+#endif
diff --git a/src/library/LawfulConversions/Relations/ByteStringAndWord8List.hs b/src/library/LawfulConversions/Relations/ByteStringAndWord8List.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ByteStringAndWord8List.hs
@@ -0,0 +1,21 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ByteStringAndWord8List where
+
+import qualified Data.ByteString
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome ByteString [Word8] where
+  to = Data.ByteString.pack
+
+instance IsSome [Word8] ByteString where
+  to = Data.ByteString.unpack
+
+instance IsMany ByteString [Word8]
+
+instance IsMany [Word8] ByteString
+
+instance Is ByteString [Word8]
+
+instance Is [Word8] ByteString
diff --git a/src/library/LawfulConversions/Relations/Int16AndWord16.hs b/src/library/LawfulConversions/Relations/Int16AndWord16.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/Int16AndWord16.hs
@@ -0,0 +1,20 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.Int16AndWord16 where
+
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Int16 Word16 where
+  to = fromIntegral
+
+instance IsSome Word16 Int16 where
+  to = fromIntegral
+
+instance IsMany Int16 Word16
+
+instance IsMany Word16 Int16
+
+instance Is Int16 Word16
+
+instance Is Word16 Int16
diff --git a/src/library/LawfulConversions/Relations/Int32AndWord32.hs b/src/library/LawfulConversions/Relations/Int32AndWord32.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/Int32AndWord32.hs
@@ -0,0 +1,20 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.Int32AndWord32 where
+
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Int32 Word32 where
+  to = fromIntegral
+
+instance IsSome Word32 Int32 where
+  to = fromIntegral
+
+instance IsMany Int32 Word32
+
+instance IsMany Word32 Int32
+
+instance Is Int32 Word32
+
+instance Is Word32 Int32
diff --git a/src/library/LawfulConversions/Relations/Int64AndWord64.hs b/src/library/LawfulConversions/Relations/Int64AndWord64.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/Int64AndWord64.hs
@@ -0,0 +1,20 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.Int64AndWord64 where
+
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Int64 Word64 where
+  to = fromIntegral
+
+instance IsSome Word64 Int64 where
+  to = fromIntegral
+
+instance IsMany Int64 Word64
+
+instance IsMany Word64 Int64
+
+instance Is Int64 Word64
+
+instance Is Word64 Int64
diff --git a/src/library/LawfulConversions/Relations/Int8AndWord8.hs b/src/library/LawfulConversions/Relations/Int8AndWord8.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/Int8AndWord8.hs
@@ -0,0 +1,20 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.Int8AndWord8 where
+
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Int8 Word8 where
+  to = fromIntegral
+
+instance IsSome Word8 Int8 where
+  to = fromIntegral
+
+instance IsMany Int8 Word8
+
+instance IsMany Word8 Int8
+
+instance Is Int8 Word8
+
+instance Is Word8 Int8
diff --git a/src/library/LawfulConversions/Relations/IntAndWord.hs b/src/library/LawfulConversions/Relations/IntAndWord.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/IntAndWord.hs
@@ -0,0 +1,20 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.IntAndWord where
+
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Int Word where
+  to = fromIntegral
+
+instance IsSome Word Int where
+  to = fromIntegral
+
+instance IsMany Int Word
+
+instance IsMany Word Int
+
+instance Is Int Word
+
+instance Is Word Int
diff --git a/src/library/LawfulConversions/Relations/IntMapAndMapOfInt.hs b/src/library/LawfulConversions/Relations/IntMapAndMapOfInt.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/IntMapAndMapOfInt.hs
@@ -0,0 +1,22 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.IntMapAndMapOfInt where
+
+import qualified Data.IntMap.Strict
+import qualified Data.Map.Strict
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome (Map Int v) (IntMap v) where
+  to = Data.Map.Strict.fromList . Data.IntMap.Strict.toList
+
+instance IsSome (IntMap v) (Map Int v) where
+  to = Data.IntMap.Strict.fromList . Data.Map.Strict.toList
+
+instance IsMany (Map Int v) (IntMap v)
+
+instance IsMany (IntMap v) (Map Int v)
+
+instance Is (Map Int v) (IntMap v)
+
+instance Is (IntMap v) (Map Int v)
diff --git a/src/library/LawfulConversions/Relations/IntSetAndSetOfInt.hs b/src/library/LawfulConversions/Relations/IntSetAndSetOfInt.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/IntSetAndSetOfInt.hs
@@ -0,0 +1,20 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.IntSetAndSetOfInt where
+
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome (Set Int) IntSet where
+  to = fromList . toList
+
+instance IsSome IntSet (Set Int) where
+  to = fromList . toList
+
+instance IsMany (Set Int) IntSet
+
+instance IsMany IntSet (Set Int)
+
+instance Is (Set Int) IntSet
+
+instance Is IntSet (Set Int)
diff --git a/src/library/LawfulConversions/Relations/LazyByteStringAndLazyByteStringBuilder.hs b/src/library/LawfulConversions/Relations/LazyByteStringAndLazyByteStringBuilder.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyByteStringAndLazyByteStringBuilder.hs
@@ -0,0 +1,21 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyByteStringAndLazyByteStringBuilder where
+
+import qualified Data.ByteString.Builder
+import qualified Data.ByteString.Lazy
+import LawfulConversions.Classes
+
+instance IsSome Data.ByteString.Lazy.ByteString Data.ByteString.Builder.Builder where
+  to = Data.ByteString.Builder.toLazyByteString
+
+instance IsSome Data.ByteString.Builder.Builder Data.ByteString.Lazy.ByteString where
+  to = Data.ByteString.Builder.lazyByteString
+
+instance IsMany Data.ByteString.Lazy.ByteString Data.ByteString.Builder.Builder
+
+instance IsMany Data.ByteString.Builder.Builder Data.ByteString.Lazy.ByteString
+
+instance Is Data.ByteString.Lazy.ByteString Data.ByteString.Builder.Builder
+
+instance Is Data.ByteString.Builder.Builder Data.ByteString.Lazy.ByteString
diff --git a/src/library/LawfulConversions/Relations/LazyByteStringAndLazyText.hs b/src/library/LawfulConversions/Relations/LazyByteStringAndLazyText.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyByteStringAndLazyText.hs
@@ -0,0 +1,13 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyByteStringAndLazyText where
+
+import qualified Data.ByteString.Lazy
+import qualified Data.Text.Lazy
+import qualified Data.Text.Lazy.Encoding
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Data.ByteString.Lazy.ByteString Data.Text.Lazy.Text where
+  to = Data.Text.Lazy.Encoding.encodeUtf8
+  maybeFrom = either (const Nothing) Just . Data.Text.Lazy.Encoding.decodeUtf8'
diff --git a/src/library/LawfulConversions/Relations/LazyByteStringAndShortByteString.hs b/src/library/LawfulConversions/Relations/LazyByteStringAndShortByteString.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyByteStringAndShortByteString.hs
@@ -0,0 +1,22 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyByteStringAndShortByteString where
+
+import qualified Data.ByteString.Lazy
+import qualified Data.ByteString.Short
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Data.ByteString.Lazy.ByteString Data.ByteString.Short.ShortByteString where
+  to = Data.ByteString.Lazy.fromStrict . Data.ByteString.Short.fromShort
+
+instance IsSome Data.ByteString.Short.ShortByteString Data.ByteString.Lazy.ByteString where
+  to = Data.ByteString.Short.toShort . Data.ByteString.Lazy.toStrict
+
+instance IsMany Data.ByteString.Lazy.ByteString Data.ByteString.Short.ShortByteString
+
+instance IsMany Data.ByteString.Short.ShortByteString Data.ByteString.Lazy.ByteString
+
+instance Is Data.ByteString.Lazy.ByteString Data.ByteString.Short.ShortByteString
+
+instance Is Data.ByteString.Short.ShortByteString Data.ByteString.Lazy.ByteString
diff --git a/src/library/LawfulConversions/Relations/LazyByteStringAndTextArray.hs b/src/library/LawfulConversions/Relations/LazyByteStringAndTextArray.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyByteStringAndTextArray.hs
@@ -0,0 +1,35 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyByteStringAndTextArray where
+
+#if !MIN_VERSION_text(2,1,0)
+
+import qualified Data.ByteString.Lazy
+import qualified Data.ByteString.Short
+import qualified Data.Text.Array
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import qualified LawfulConversions.TextCompat.Array
+
+instance IsSome Data.ByteString.Lazy.ByteString Data.Text.Array.Array where
+  to =
+    Data.ByteString.Lazy.fromStrict
+      . Data.ByteString.Short.fromShort
+      . LawfulConversions.TextCompat.Array.toShortByteString
+
+instance IsSome Data.Text.Array.Array Data.ByteString.Lazy.ByteString where
+  to =
+    LawfulConversions.TextCompat.Array.fromShortByteString
+      . Data.ByteString.Short.toShort
+      . Data.ByteString.Lazy.toStrict
+
+instance IsMany Data.Text.Array.Array Data.ByteString.Lazy.ByteString
+
+instance IsMany Data.ByteString.Lazy.ByteString Data.Text.Array.Array
+
+instance Is Data.Text.Array.Array Data.ByteString.Lazy.ByteString
+
+instance Is Data.ByteString.Lazy.ByteString Data.Text.Array.Array
+
+#endif
diff --git a/src/library/LawfulConversions/Relations/LazyByteStringAndWord8List.hs b/src/library/LawfulConversions/Relations/LazyByteStringAndWord8List.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyByteStringAndWord8List.hs
@@ -0,0 +1,21 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyByteStringAndWord8List where
+
+import qualified Data.ByteString.Lazy
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Data.ByteString.Lazy.ByteString [Word8] where
+  to = Data.ByteString.Lazy.pack
+
+instance IsSome [Word8] Data.ByteString.Lazy.ByteString where
+  to = Data.ByteString.Lazy.unpack
+
+instance IsMany Data.ByteString.Lazy.ByteString [Word8]
+
+instance IsMany [Word8] Data.ByteString.Lazy.ByteString
+
+instance Is Data.ByteString.Lazy.ByteString [Word8]
+
+instance Is [Word8] Data.ByteString.Lazy.ByteString
diff --git a/src/library/LawfulConversions/Relations/LazyByteStringBuilderAndShortByteString.hs b/src/library/LawfulConversions/Relations/LazyByteStringBuilderAndShortByteString.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyByteStringBuilderAndShortByteString.hs
@@ -0,0 +1,24 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyByteStringBuilderAndShortByteString where
+
+import qualified Data.ByteString.Builder
+import qualified Data.ByteString.Lazy
+import qualified Data.ByteString.Short
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Data.ByteString.Builder.Builder Data.ByteString.Short.ShortByteString where
+  to = Data.ByteString.Builder.shortByteString
+
+instance IsSome Data.ByteString.Short.ShortByteString Data.ByteString.Builder.Builder where
+  to = Data.ByteString.Short.toShort . Data.ByteString.Lazy.toStrict . Data.ByteString.Builder.toLazyByteString
+  maybeFrom = Just . Data.ByteString.Builder.shortByteString
+
+instance IsMany Data.ByteString.Builder.Builder Data.ByteString.Short.ShortByteString
+
+instance IsMany Data.ByteString.Short.ShortByteString Data.ByteString.Builder.Builder
+
+instance Is Data.ByteString.Builder.Builder Data.ByteString.Short.ShortByteString
+
+instance Is Data.ByteString.Short.ShortByteString Data.ByteString.Builder.Builder
diff --git a/src/library/LawfulConversions/Relations/LazyByteStringBuilderAndTextArray.hs b/src/library/LawfulConversions/Relations/LazyByteStringBuilderAndTextArray.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyByteStringBuilderAndTextArray.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyByteStringBuilderAndTextArray where
+
+#if !MIN_VERSION_text(2,1,0)
+
+import qualified Data.ByteString.Builder
+import qualified Data.ByteString.Lazy
+import qualified Data.ByteString.Short
+import qualified Data.Text.Array
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import qualified LawfulConversions.TextCompat.Array
+
+instance IsSome Data.ByteString.Builder.Builder Data.Text.Array.Array where
+  to = Data.ByteString.Builder.shortByteString . LawfulConversions.TextCompat.Array.toShortByteString
+
+instance IsSome Data.Text.Array.Array Data.ByteString.Builder.Builder where
+  to =
+    LawfulConversions.TextCompat.Array.fromShortByteString
+      . Data.ByteString.Short.toShort
+      . Data.ByteString.Lazy.toStrict
+      . Data.ByteString.Builder.toLazyByteString
+
+instance IsMany Data.Text.Array.Array Data.ByteString.Builder.Builder
+
+instance IsMany Data.ByteString.Builder.Builder Data.Text.Array.Array
+
+instance Is Data.Text.Array.Array Data.ByteString.Builder.Builder
+
+instance Is Data.ByteString.Builder.Builder Data.Text.Array.Array
+
+#endif
diff --git a/src/library/LawfulConversions/Relations/LazyByteStringBuilderAndWord8List.hs b/src/library/LawfulConversions/Relations/LazyByteStringBuilderAndWord8List.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyByteStringBuilderAndWord8List.hs
@@ -0,0 +1,22 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyByteStringBuilderAndWord8List where
+
+import qualified Data.ByteString.Builder
+import qualified Data.ByteString.Lazy
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Data.ByteString.Builder.Builder [Word8] where
+  to = Data.ByteString.Builder.lazyByteString . Data.ByteString.Lazy.pack
+
+instance IsSome [Word8] Data.ByteString.Builder.Builder where
+  to = Data.ByteString.Lazy.unpack . Data.ByteString.Builder.toLazyByteString
+
+instance IsMany Data.ByteString.Builder.Builder [Word8]
+
+instance IsMany [Word8] Data.ByteString.Builder.Builder
+
+instance Is Data.ByteString.Builder.Builder [Word8]
+
+instance Is [Word8] Data.ByteString.Builder.Builder
diff --git a/src/library/LawfulConversions/Relations/LazyTextAndLazyTextBuilder.hs b/src/library/LawfulConversions/Relations/LazyTextAndLazyTextBuilder.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyTextAndLazyTextBuilder.hs
@@ -0,0 +1,24 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyTextAndLazyTextBuilder where
+
+import qualified Data.Text.Lazy
+import qualified Data.Text.Lazy.Builder
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Data.Text.Lazy.Text Data.Text.Lazy.Builder.Builder where
+  to = Data.Text.Lazy.Builder.toLazyText
+  maybeFrom = Just . Data.Text.Lazy.Builder.fromLazyText
+
+instance IsSome Data.Text.Lazy.Builder.Builder Data.Text.Lazy.Text where
+  to = Data.Text.Lazy.Builder.fromLazyText
+  maybeFrom = Just . Data.Text.Lazy.Builder.toLazyText
+
+instance IsMany Data.Text.Lazy.Text Data.Text.Lazy.Builder.Builder
+
+instance IsMany Data.Text.Lazy.Builder.Builder Data.Text.Lazy.Text
+
+instance Is Data.Text.Lazy.Text Data.Text.Lazy.Builder.Builder
+
+instance Is Data.Text.Lazy.Builder.Builder Data.Text.Lazy.Text
diff --git a/src/library/LawfulConversions/Relations/LazyTextAndStrictTextBuilder.hs b/src/library/LawfulConversions/Relations/LazyTextAndStrictTextBuilder.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyTextAndStrictTextBuilder.hs
@@ -0,0 +1,27 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyTextAndStrictTextBuilder where
+
+#if MIN_VERSION_text(2,0,2)
+
+import qualified Data.Text.Encoding
+import qualified Data.Text.Lazy
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Data.Text.Lazy.Text Data.Text.Encoding.StrictBuilder where
+  to = Data.Text.Lazy.fromStrict . Data.Text.Encoding.strictBuilderToText
+
+instance IsSome Data.Text.Encoding.StrictBuilder Data.Text.Lazy.Text where
+  to = Data.Text.Encoding.textToStrictBuilder . Data.Text.Lazy.toStrict
+
+instance IsMany Data.Text.Lazy.Text Data.Text.Encoding.StrictBuilder
+
+instance IsMany Data.Text.Encoding.StrictBuilder Data.Text.Lazy.Text
+
+instance Is Data.Text.Lazy.Text Data.Text.Encoding.StrictBuilder
+
+instance Is Data.Text.Encoding.StrictBuilder Data.Text.Lazy.Text
+
+#endif
diff --git a/src/library/LawfulConversions/Relations/LazyTextAndString.hs b/src/library/LawfulConversions/Relations/LazyTextAndString.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyTextAndString.hs
@@ -0,0 +1,12 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyTextAndString where
+
+import qualified Data.Text.Lazy
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import LawfulConversions.Relations.StringAndText ()
+
+instance IsSome String Data.Text.Lazy.Text where
+  to = Data.Text.Lazy.unpack
+  maybeFrom = fmap Data.Text.Lazy.fromStrict . maybeFrom
diff --git a/src/library/LawfulConversions/Relations/LazyTextAndText.hs b/src/library/LawfulConversions/Relations/LazyTextAndText.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyTextAndText.hs
@@ -0,0 +1,21 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyTextAndText where
+
+import qualified Data.Text.Lazy
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Data.Text.Lazy.Text Text where
+  to = Data.Text.Lazy.fromStrict
+
+instance IsSome Text Data.Text.Lazy.Text where
+  to = Data.Text.Lazy.toStrict
+
+instance IsMany Data.Text.Lazy.Text Text
+
+instance IsMany Text Data.Text.Lazy.Text
+
+instance Is Data.Text.Lazy.Text Text
+
+instance Is Text Data.Text.Lazy.Text
diff --git a/src/library/LawfulConversions/Relations/LazyTextBuilderAndStrictTextBuilder.hs b/src/library/LawfulConversions/Relations/LazyTextBuilderAndStrictTextBuilder.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyTextBuilderAndStrictTextBuilder.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyTextBuilderAndStrictTextBuilder where
+
+#if MIN_VERSION_text(2,0,2)
+
+import qualified Data.Text.Encoding
+import qualified Data.Text.Lazy
+import qualified Data.Text.Lazy.Builder
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Data.Text.Lazy.Builder.Builder Data.Text.Encoding.StrictBuilder where
+  to = Data.Text.Lazy.Builder.fromText . Data.Text.Encoding.strictBuilderToText
+
+instance IsSome Data.Text.Encoding.StrictBuilder Data.Text.Lazy.Builder.Builder where
+  to = Data.Text.Encoding.textToStrictBuilder . Data.Text.Lazy.toStrict . Data.Text.Lazy.Builder.toLazyText
+
+instance IsMany Data.Text.Lazy.Builder.Builder Data.Text.Encoding.StrictBuilder
+
+instance IsMany Data.Text.Encoding.StrictBuilder Data.Text.Lazy.Builder.Builder
+
+instance Is Data.Text.Lazy.Builder.Builder Data.Text.Encoding.StrictBuilder
+
+instance Is Data.Text.Encoding.StrictBuilder Data.Text.Lazy.Builder.Builder
+
+#endif
diff --git a/src/library/LawfulConversions/Relations/LazyTextBuilderAndString.hs b/src/library/LawfulConversions/Relations/LazyTextBuilderAndString.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyTextBuilderAndString.hs
@@ -0,0 +1,13 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyTextBuilderAndString where
+
+import qualified Data.Text.Lazy
+import qualified Data.Text.Lazy.Builder
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import LawfulConversions.Relations.StringAndText ()
+
+instance IsSome String Data.Text.Lazy.Builder.Builder where
+  to = Data.Text.Lazy.unpack . Data.Text.Lazy.Builder.toLazyText
+  maybeFrom = fmap Data.Text.Lazy.Builder.fromText . maybeFrom
diff --git a/src/library/LawfulConversions/Relations/LazyTextBuilderAndText.hs b/src/library/LawfulConversions/Relations/LazyTextBuilderAndText.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/LazyTextBuilderAndText.hs
@@ -0,0 +1,24 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.LazyTextBuilderAndText where
+
+import qualified Data.Text.Lazy
+import qualified Data.Text.Lazy.Builder
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Data.Text.Lazy.Builder.Builder Text where
+  to = Data.Text.Lazy.Builder.fromText
+  maybeFrom = Just . Data.Text.Lazy.toStrict . Data.Text.Lazy.Builder.toLazyText
+
+instance IsSome Text Data.Text.Lazy.Builder.Builder where
+  to = Data.Text.Lazy.toStrict . Data.Text.Lazy.Builder.toLazyText
+  maybeFrom = Just . Data.Text.Lazy.Builder.fromText
+
+instance IsMany Data.Text.Lazy.Builder.Builder Text
+
+instance IsMany Text Data.Text.Lazy.Builder.Builder
+
+instance Is Data.Text.Lazy.Builder.Builder Text
+
+instance Is Text Data.Text.Lazy.Builder.Builder
diff --git a/src/library/LawfulConversions/Relations/ListAndSeq.hs b/src/library/LawfulConversions/Relations/ListAndSeq.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ListAndSeq.hs
@@ -0,0 +1,21 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ListAndSeq where
+
+import qualified Data.Sequence
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome [a] (Seq a) where
+  to = toList
+
+instance IsSome (Seq a) [a] where
+  to = Data.Sequence.fromList
+
+instance IsMany [a] (Seq a)
+
+instance IsMany (Seq a) [a]
+
+instance Is [a] (Seq a)
+
+instance Is (Seq a) [a]
diff --git a/src/library/LawfulConversions/Relations/ShortByteStringAndTextArray.hs b/src/library/LawfulConversions/Relations/ShortByteStringAndTextArray.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ShortByteStringAndTextArray.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ShortByteStringAndTextArray where
+
+#if !MIN_VERSION_text(2,1,0)
+
+import qualified Data.ByteString.Short
+import qualified Data.Text.Array
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import qualified LawfulConversions.TextCompat.Array
+
+instance IsSome Data.ByteString.Short.ShortByteString Data.Text.Array.Array where
+  to = LawfulConversions.TextCompat.Array.toShortByteString
+
+instance IsSome Data.Text.Array.Array Data.ByteString.Short.ShortByteString where
+  to = LawfulConversions.TextCompat.Array.fromShortByteString
+
+instance IsMany Data.ByteString.Short.ShortByteString Data.Text.Array.Array
+
+instance IsMany Data.Text.Array.Array Data.ByteString.Short.ShortByteString
+
+instance Is Data.ByteString.Short.ShortByteString Data.Text.Array.Array
+
+instance Is Data.Text.Array.Array Data.ByteString.Short.ShortByteString
+
+#endif
diff --git a/src/library/LawfulConversions/Relations/ShortByteStringAndWord8List.hs b/src/library/LawfulConversions/Relations/ShortByteStringAndWord8List.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/ShortByteStringAndWord8List.hs
@@ -0,0 +1,22 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.ShortByteStringAndWord8List where
+
+import qualified Data.ByteString.Short
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import LawfulConversions.Relations.ByteArrayAndShortByteString ()
+
+instance IsSome [Word8] Data.ByteString.Short.ShortByteString where
+  to = Data.ByteString.Short.unpack
+
+instance IsSome Data.ByteString.Short.ShortByteString [Word8] where
+  to = Data.ByteString.Short.pack
+
+instance IsMany [Word8] Data.ByteString.Short.ShortByteString
+
+instance IsMany Data.ByteString.Short.ShortByteString [Word8]
+
+instance Is [Word8] Data.ByteString.Short.ShortByteString
+
+instance Is Data.ByteString.Short.ShortByteString [Word8]
diff --git a/src/library/LawfulConversions/Relations/StrictTextBuilderAndString.hs b/src/library/LawfulConversions/Relations/StrictTextBuilderAndString.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/StrictTextBuilderAndString.hs
@@ -0,0 +1,17 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.StrictTextBuilderAndString where
+
+#if MIN_VERSION_text(2,0,2)
+
+import qualified Data.Text.Encoding
+import LawfulConversions.Classes
+import LawfulConversions.Relations.StringAndText ()
+import LawfulConversions.Prelude
+
+instance IsSome String Data.Text.Encoding.StrictBuilder where
+  to = to . Data.Text.Encoding.strictBuilderToText
+  maybeFrom = fmap Data.Text.Encoding.textToStrictBuilder . maybeFrom
+
+#endif
diff --git a/src/library/LawfulConversions/Relations/StrictTextBuilderAndText.hs b/src/library/LawfulConversions/Relations/StrictTextBuilderAndText.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/StrictTextBuilderAndText.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.StrictTextBuilderAndText where
+
+#if MIN_VERSION_text(2,0,2)
+
+import qualified Data.Text.Encoding
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome Text Data.Text.Encoding.StrictBuilder where
+  to = Data.Text.Encoding.strictBuilderToText
+
+instance IsSome Data.Text.Encoding.StrictBuilder Text where
+  to = Data.Text.Encoding.textToStrictBuilder
+
+instance IsMany Text Data.Text.Encoding.StrictBuilder
+
+instance IsMany Data.Text.Encoding.StrictBuilder Text
+
+instance Is Text Data.Text.Encoding.StrictBuilder
+
+instance Is Data.Text.Encoding.StrictBuilder Text
+
+#endif
diff --git a/src/library/LawfulConversions/Relations/StringAndText.hs b/src/library/LawfulConversions/Relations/StringAndText.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/StringAndText.hs
@@ -0,0 +1,16 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.StringAndText where
+
+import qualified Data.Text as Text
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+
+instance IsSome String Text where
+  to = Text.unpack
+  maybeFrom string =
+    -- FIXME: Optimize.
+    let text = Text.pack string
+     in if string == Text.unpack text
+          then Just text
+          else Nothing
diff --git a/src/library/LawfulConversions/Relations/TextArrayAndWord8List.hs b/src/library/LawfulConversions/Relations/TextArrayAndWord8List.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/Relations/TextArrayAndWord8List.hs
@@ -0,0 +1,24 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module LawfulConversions.Relations.TextArrayAndWord8List where
+
+#if !MIN_VERSION_text(2,1,0)
+
+import qualified Data.ByteString.Short
+import qualified Data.Text.Array
+import LawfulConversions.Classes
+import LawfulConversions.Prelude
+import qualified LawfulConversions.TextCompat.Array
+
+instance IsSome Data.Text.Array.Array [Word8] where
+  to = LawfulConversions.TextCompat.Array.fromShortByteString . Data.ByteString.Short.pack
+
+instance IsSome [Word8] Data.Text.Array.Array where
+  to = Data.ByteString.Short.unpack . LawfulConversions.TextCompat.Array.toShortByteString
+
+instance Is Data.Text.Array.Array [Word8]
+
+instance Is [Word8] Data.Text.Array.Array
+
+#endif
diff --git a/src/library/LawfulConversions/TextCompat/Array.hs b/src/library/LawfulConversions/TextCompat/Array.hs
new file mode 100644
--- /dev/null
+++ b/src/library/LawfulConversions/TextCompat/Array.hs
@@ -0,0 +1,45 @@
+{-# LANGUAGE CPP #-}
+
+module LawfulConversions.TextCompat.Array where
+
+import qualified Data.ByteString.Short
+import qualified Data.ByteString.Short.Internal
+import qualified Data.Primitive.ByteArray
+import Data.Text.Array
+import GHC.Exts (ByteArray#)
+
+{-# INLINE toUnliftedByteArray #-}
+toUnliftedByteArray :: Array -> ByteArray#
+#if MIN_VERSION_text(2,0,0)
+toUnliftedByteArray (ByteArray a) = a
+#else
+toUnliftedByteArray (Array a) = a
+#endif
+
+{-# INLINE fromUnliftedByteArray #-}
+fromUnliftedByteArray :: ByteArray# -> Array
+#if MIN_VERSION_text(2,0,0)
+fromUnliftedByteArray = ByteArray
+#else
+fromUnliftedByteArray = Array
+#endif
+
+{-# INLINE fromShortByteString #-}
+fromShortByteString :: Data.ByteString.Short.ShortByteString -> Array
+fromShortByteString (Data.ByteString.Short.Internal.SBS arr) =
+  fromUnliftedByteArray arr
+
+{-# INLINE toShortByteString #-}
+toShortByteString :: Array -> Data.ByteString.Short.ShortByteString
+toShortByteString a =
+  Data.ByteString.Short.Internal.SBS (toUnliftedByteArray a)
+
+{-# INLINE fromByteArray #-}
+fromByteArray :: Data.Primitive.ByteArray.ByteArray -> Array
+fromByteArray (Data.Primitive.ByteArray.ByteArray arr) =
+  fromUnliftedByteArray arr
+
+{-# INLINE toByteArray #-}
+toByteArray :: Array -> Data.Primitive.ByteArray.ByteArray
+toByteArray a =
+  Data.Primitive.ByteArray.ByteArray (toUnliftedByteArray a)
diff --git a/src/test/Main.hs b/src/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/test/Main.hs
@@ -0,0 +1,127 @@
+module Main where
+
+import qualified Data.ByteString.Builder as ByteStringBuilder
+import qualified Data.ByteString.Lazy as ByteStringLazy
+import qualified Data.ByteString.Short as ByteStringShort
+import qualified Data.Primitive.ByteArray as PrimitiveByteArray
+import qualified Data.Text.Lazy as TextLazy
+import qualified Data.Text.Lazy.Builder as TextLazyBuilder
+import LawfulConversions
+import Rebase.Prelude
+import Test.ExtraInstances ()
+import Test.Tasty
+import Test.Tasty.QuickCheck hiding ((.&.))
+
+main :: IO ()
+main = defaultMain allTests
+
+allTests :: TestTree
+allTests =
+  testGroup "All" $
+    [ testPair @[Word8] @ByteString Proxy Proxy,
+      testPair @[Word8] @ByteStringLazy.ByteString Proxy Proxy,
+      testPair @[Word8] @ByteStringShort.ShortByteString Proxy Proxy,
+      testPair @[Word8] @ByteStringBuilder.Builder Proxy Proxy,
+      testPair @[Word8] @PrimitiveByteArray.ByteArray Proxy Proxy,
+      testPair @[Word8] @[Word8] Proxy Proxy,
+      testPair @[Word8] @(Vector Word8) Proxy Proxy,
+      testPair @[Word8] @(Seq Word8) Proxy Proxy,
+      testPair @Text @Text Proxy Proxy,
+      testPair @Text @TextLazy.Text Proxy Proxy,
+      testPair @Text @TextLazyBuilder.Builder Proxy Proxy,
+      testPair @TextLazy.Text @TextLazy.Text Proxy Proxy,
+      testPair @TextLazy.Text @Text Proxy Proxy,
+      testPair @TextLazy.Text @TextLazyBuilder.Builder Proxy Proxy,
+      testPair @TextLazyBuilder.Builder @TextLazyBuilder.Builder Proxy Proxy,
+      testPair @TextLazyBuilder.Builder @Text Proxy Proxy,
+      testPair @TextLazyBuilder.Builder @TextLazy.Text Proxy Proxy,
+      testPair @ByteString @ByteString Proxy Proxy,
+      testPair @ByteString @[Word8] Proxy Proxy,
+      testPair @ByteString @ByteStringLazy.ByteString Proxy Proxy,
+      testPair @ByteString @ByteStringShort.ShortByteString Proxy Proxy,
+      testPair @ByteString @ByteStringBuilder.Builder Proxy Proxy,
+      testPair @ByteString @PrimitiveByteArray.ByteArray Proxy Proxy,
+      testPair @ByteStringLazy.ByteString @ByteStringLazy.ByteString Proxy Proxy,
+      testPair @ByteStringLazy.ByteString @[Word8] Proxy Proxy,
+      testPair @ByteStringLazy.ByteString @ByteString Proxy Proxy,
+      testPair @ByteStringLazy.ByteString @ByteStringShort.ShortByteString Proxy Proxy,
+      testPair @ByteStringLazy.ByteString @ByteStringBuilder.Builder Proxy Proxy,
+      testPair @ByteStringLazy.ByteString @PrimitiveByteArray.ByteArray Proxy Proxy,
+      testPair @ByteStringShort.ShortByteString @ByteStringShort.ShortByteString Proxy Proxy,
+      testPair @ByteStringShort.ShortByteString @[Word8] Proxy Proxy,
+      testPair @ByteStringShort.ShortByteString @ByteString Proxy Proxy,
+      testPair @ByteStringShort.ShortByteString @ByteStringLazy.ByteString Proxy Proxy,
+      testPair @ByteStringShort.ShortByteString @ByteStringBuilder.Builder Proxy Proxy,
+      testPair @ByteStringShort.ShortByteString @PrimitiveByteArray.ByteArray Proxy Proxy,
+      testPair @ByteStringBuilder.Builder @ByteStringBuilder.Builder Proxy Proxy,
+      testPair @ByteStringBuilder.Builder @[Word8] Proxy Proxy,
+      testPair @ByteStringBuilder.Builder @ByteString Proxy Proxy,
+      testPair @ByteStringBuilder.Builder @ByteStringLazy.ByteString Proxy Proxy,
+      testPair @ByteStringBuilder.Builder @ByteStringShort.ShortByteString Proxy Proxy,
+      testPair @ByteStringBuilder.Builder @PrimitiveByteArray.ByteArray Proxy Proxy,
+      testPair @PrimitiveByteArray.ByteArray @PrimitiveByteArray.ByteArray Proxy Proxy,
+      testPair @PrimitiveByteArray.ByteArray @[Word8] Proxy Proxy,
+      testPair @PrimitiveByteArray.ByteArray @ByteStringShort.ShortByteString Proxy Proxy,
+      testPair @PrimitiveByteArray.ByteArray @ByteString Proxy Proxy,
+      testPair @PrimitiveByteArray.ByteArray @ByteStringLazy.ByteString Proxy Proxy,
+      testPair @PrimitiveByteArray.ByteArray @ByteStringBuilder.Builder Proxy Proxy,
+      testPair @(Vector Word8) @(Vector Word8) Proxy Proxy,
+      testPair @(Vector Word8) @[Word8] Proxy Proxy,
+      testPair @(Vector Word8) @(Seq Word8) Proxy Proxy,
+      testPair @(Seq Word8) @(Seq Word8) Proxy Proxy,
+      testPair @(Seq Word8) @[Word8] Proxy Proxy,
+      testPair @(Seq Word8) @(Vector Word8) Proxy Proxy,
+      testPair @(Set Word8) @(Set Word8) Proxy Proxy,
+      testPair @(Set Int) @IntSet Proxy Proxy,
+      testPair @IntSet @IntSet Proxy Proxy,
+      testPair @IntSet @(Set Int) Proxy Proxy,
+      testPair @(Map Word8 Word8) @(Map Word8 Word8) Proxy Proxy,
+      testPair @(Map Int Word8) @(IntMap Word8) Proxy Proxy,
+      testPair @(IntMap Word8) @(IntMap Word8) Proxy Proxy,
+      testPair @(IntMap Word8) @(Map Int Word8) Proxy Proxy,
+      testPair @(Maybe Word8) @(Maybe Word8) Proxy Proxy,
+      testPair @(Either Word8 Word8) @(Either Word8 Word8) Proxy Proxy,
+      testPair @(First Word8) @(First Word8) Proxy Proxy,
+      testPair @(Last Word8) @(Last Word8) Proxy Proxy,
+      testPair @(Product Word8) @(Product Word8) Proxy Proxy,
+      testPair @(Sum Word8) @(Sum Word8) Proxy Proxy,
+      testPair @Bool @Bool Proxy Proxy,
+      testPair @Char @Char Proxy Proxy,
+      testPair @Double @Double Proxy Proxy,
+      testPair @Float @Float Proxy Proxy,
+      testPair @Int @Int Proxy Proxy,
+      testPair @Int @Word Proxy Proxy,
+      testPair @Int16 @Int16 Proxy Proxy,
+      testPair @Int16 @Word16 Proxy Proxy,
+      testPair @Int32 @Int32 Proxy Proxy,
+      testPair @Int32 @Word32 Proxy Proxy,
+      testPair @Int64 @Int64 Proxy Proxy,
+      testPair @Int64 @Word64 Proxy Proxy,
+      testPair @Int8 @Int8 Proxy Proxy,
+      testPair @Int8 @Word8 Proxy Proxy,
+      testPair @Integer @Integer Proxy Proxy,
+      testPair @Rational @Rational Proxy Proxy,
+      testPair @Word @Int Proxy Proxy,
+      testPair @Word @Word Proxy Proxy,
+      testPair @Word16 @Int16 Proxy Proxy,
+      testPair @Word16 @Word16 Proxy Proxy,
+      testPair @Word32 @Int32 Proxy Proxy,
+      testPair @Word32 @Word32 Proxy Proxy,
+      testPair @Word64 @Int64 Proxy Proxy,
+      testPair @Word64 @Word64 Proxy Proxy,
+      testPair @Word8 @Int8 Proxy Proxy,
+      testPair @Word8 @Word8 Proxy Proxy
+    ]
+
+testPair :: (Is a b, Eq a, Eq b, Arbitrary a, Show a, Arbitrary b, Show b, Typeable a, Typeable b) => Proxy a -> Proxy b -> TestTree
+testPair superp subp =
+  isProperties superp subp
+    & fmap (uncurry testProperty)
+    & testGroup groupName
+  where
+    groupName =
+      mconcat
+        [ show (typeOf (asProxyTypeOf undefined superp)),
+          "/",
+          show (typeOf (asProxyTypeOf undefined subp))
+        ]
diff --git a/src/test/Test/ExtraInstances.hs b/src/test/Test/ExtraInstances.hs
new file mode 100644
--- /dev/null
+++ b/src/test/Test/ExtraInstances.hs
@@ -0,0 +1,20 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module Test.ExtraInstances () where
+
+import qualified Data.ByteString.Builder as ByteStringBuilder
+import qualified Data.Text.Lazy.Builder as TextLazyBuilder
+import Rebase.Prelude
+import Test.QuickCheck
+import Test.QuickCheck.Instances ()
+
+instance Arbitrary TextLazyBuilder.Builder where
+  arbitrary = TextLazyBuilder.fromText <$> arbitrary
+  shrink = shrinkMap TextLazyBuilder.fromLazyText TextLazyBuilder.toLazyText
+
+instance Eq ByteStringBuilder.Builder where
+  (==) = on (==) ByteStringBuilder.toLazyByteString
+
+instance Arbitrary ByteStringBuilder.Builder where
+  arbitrary = ByteStringBuilder.byteString <$> arbitrary
+  shrink = shrinkMap ByteStringBuilder.lazyByteString ByteStringBuilder.toLazyByteString
