diff --git a/Changelog.md b/Changelog.md
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,4 +1,34 @@
-# next
+# 0.4.3
+
+- Use automatic flags for compatibility conditionals
+
+# 0.4.1.1
+
+- Support GHC-7.2 and GHC-7.0.
+
+# 0.4.1
+
+- Mark `MkSolo` pattern synonym as `COMPLETE`
+
+# 0.4
+
+- Rename constructor to `MkSolo` as in `base-4.17`.
+  The compatibility pattern synonym is provided.
+- Add `Foldable1 Solo` instance
+
+# 0.3.1
+
+- Add `Data.Tuple.Solo.TH` with `tupE` using `Solo` from this package
+- Add `Hashable` and `Hashable1` instances
+- Drop GHC-7.0 and GHC-7.2 support
+
+# 0.3
+
+- Rename `OneTuple` to `Solo`
+- Add `Typeable`, `Data`, `MonadZip`, `Eq1`, `Ord1`, `Show1`, `Read1`,
+  `Generic` and `Generic1` instances
+
+# 0.2.2.1
 
 - Compatible with GHC-8.6
 
diff --git a/OneTuple.cabal b/OneTuple.cabal
--- a/OneTuple.cabal
+++ b/OneTuple.cabal
@@ -1,14 +1,16 @@
-cabal-version:      >=1.10
+cabal-version:      1.12
 name:               OneTuple
-version:            0.2.2.1
+version:            0.4.3
 synopsis:           Singleton Tuple
 category:           Data
 description:
-  This package provides a singleton tuple data type
+  This package is a compatibility package for a singleton data type
   .
-  > data OneTuple a = OneTuple a
+  > data Solo a = MkSolo a
   .
   Note: it's not a @newtype@
+  .
+  @Solo@ is available in @base-4.16@ (GHC-9.2).
 
 copyright:          (c) John Dorsey 2008
 license:            BSD3
@@ -20,18 +22,17 @@
 stability:          experimental
 build-type:         Simple
 tested-with:
-  GHC ==7.0.4
-   || ==7.2.2
-   || ==7.4.2
-   || ==7.6.3
-   || ==7.8.4
-   || ==7.10.3
-   || ==8.0.2
-   || ==8.2.2
-   || ==8.4.4
-   || ==8.6.5
-   || ==8.8.3
-   || ==8.10.1
+  GHC ==8.6.5
+   || ==8.8.4
+   || ==8.10.7
+   || ==9.0.2
+   || ==9.2.8
+   || ==9.4.8
+   || ==9.6.4
+   || ==9.8.6
+   || ==9.10.2
+   || ==9.12.2
+   || ==9.14.1
 
 extra-source-files: Changelog.md
 
@@ -39,11 +40,77 @@
   type:     git
   location: https://github.com/phadej/OneTuple.git
 
+flag base-ge-4-15
+  description: @base >=4.15@ (GHC-9.0)
+  default:     True
+  manual:      False
+
+flag base-ge-4-16
+  description: @base >=4.16@ (GHC-9.2)
+  default:     True
+  manual:      False
+
 library
   default-language: Haskell98
-  exposed-modules:  Data.Tuple.OneTuple
+  exposed-modules:
+    Data.Tuple.OneTuple
+    Data.Tuple.Solo
+    Data.Tuple.Solo.TH
+
   hs-source-dirs:   src
-  build-depends:    base >=4.3 && <4.15
+  build-depends:
+      base              >=4.12 && <4.23
+    , template-haskell
 
+  if flag(base-ge-4-15)
+    build-depends: ghc-prim
+
+  else
+    build-depends: hashable >=1.3.5.0 && <1.6
+
+  if !flag(base-ge-4-15)
+    build-depends: foldable1-classes-compat >=0.1 && <0.2
+
+  if !flag(base-ge-4-16)
+    build-depends: base-orphans >=0.8.6
+
+  -- flag selection forcing conditionals
+  if flag(base-ge-4-15)
+    build-depends: base >=4.15
+
+  else
+    build-depends: base <4.15
+
+  if flag(base-ge-4-16)
+    build-depends: base >=4.16
+
+  else
+    build-depends: base <4.16
+
+test-suite instances
+  type:             exitcode-stdio-1.0
+  default-language: Haskell98
+  hs-source-dirs:   test
+  main-is:          instances.hs
+  build-depends:
+      base
+    , hashable
+    , OneTuple
+
   if !impl(ghc >=8.0)
-    build-depends: semigroups >=0.18.4 && <0.20
+    build-depends:
+        semigroups
+      , transformers
+      , transformers-compat
+
+  if !impl(ghc >=9.6)
+    build-depends: foldable1-classes-compat >=0.1 && <0.2
+
+test-suite th
+  type:             exitcode-stdio-1.0
+  default-language: Haskell98
+  hs-source-dirs:   test
+  main-is:          th.hs
+  build-depends:
+      base
+    , OneTuple
diff --git a/src/Data/Tuple/OneTuple.hs b/src/Data/Tuple/OneTuple.hs
--- a/src/Data/Tuple/OneTuple.hs
+++ b/src/Data/Tuple/OneTuple.hs
@@ -1,85 +1,24 @@
--- |OneTuple fills the /tuple gap/ with a singleton tuple.
---
--- OneTuple /does not support/ the usual parenthesized tuple syntax.
---
--- OneTuple
---
---   * has the expected laziness properties
---
---   * can be pattern-matched
---
---   * ships with instances for several standard type classes,
---     including all those supported by H98-standard tuples
+{-# LANGUAGE PatternSynonyms #-}
+-- | This is a module to help migration from @OneTuple@ to @Solo@.
+-- Migrate to use "Data.Tuple" from @base-4.16@ or "Data.Tuple.Solo" with all GHCs.
 --
---   * requires no language extensions, except for hierarchical modules
-
-module Data.Tuple.OneTuple (OneTuple(OneTuple), only) where
-
-import Control.Applicative (Applicative (..))
-import Control.Monad       (ap)
-import Control.Monad.Fix   (MonadFix (..))
-import Data.Foldable       (Foldable (..))
-import Data.Ix             (Ix (..))
-import Data.Monoid         (Monoid (..))
-import Data.Semigroup      (Semigroup (..))
-import Data.Traversable    (Traversable (..))
-
--- |OneTuple is the singleton tuple data type.
-data OneTuple a
-    = OneTuple a  -- ^ singleton tuple constructor
-    deriving (Eq,Ord,Bounded,Show,Read)
-
--- |The 'only' function extracts the OneTuple's only member.
--- (Compare to 'fst' and 'snd'.)
-only :: OneTuple a -- ^ takes a singleton tuple argument
-     -> a          -- ^ returns the only element in the tuple
-only (OneTuple x) = x
-
-instance (Enum a) => Enum (OneTuple a) where
-    succ = fmap succ
-    pred = fmap pred
-    toEnum = pure . toEnum
-    fromEnum (OneTuple x) = fromEnum x
-
-instance (Ix a) => Ix (OneTuple a) where
-    range   (OneTuple x, OneTuple y) = map OneTuple (range (x,y))
-    index   (OneTuple x, OneTuple y) (OneTuple z) = index   (x,y) z
-    inRange (OneTuple x, OneTuple y) (OneTuple z) = inRange (x,y) z
-
-instance Foldable OneTuple where
-    fold (OneTuple m) = m
-    foldMap f (OneTuple x) = f x
-    foldr f b (OneTuple x) = f x b
-    foldl f a (OneTuple x) = f a x
-    foldr1 _f (OneTuple x) = x
-    foldl1 _f (OneTuple x) = x
-
-instance Traversable OneTuple where
-    traverse f (OneTuple x) = fmap OneTuple (f x)
-    sequenceA (OneTuple x) = fmap OneTuple x
-
-instance Functor OneTuple where
-    fmap f (OneTuple x) = OneTuple (f x)
-
-instance Applicative OneTuple where
-    pure = OneTuple
-
-    OneTuple f <*> OneTuple x = OneTuple (f x)
-    _ *> x = x
-    x <* _ = x
+-- The pattern synonym is provided for GHCs supporting pattern synonyms (7.8+)
+module Data.Tuple.OneTuple
+{-# DEPRECATED "Use Data.Tuple.Solo" #-}
+(
+    OneTuple,
+    pattern OneTuple,
+    only,
+) where
 
-instance Monad OneTuple where
-    return = pure
-    (>>) = (*>)
-    (OneTuple x) >>= f = f x
+import Data.Tuple.Solo
 
-instance (Semigroup a) => Semigroup (OneTuple a) where
-    OneTuple x <> OneTuple y = OneTuple (x <> y)
+type OneTuple = Solo
 
-instance (Monoid a) => Monoid (OneTuple a) where
-    mempty = OneTuple mempty
-    mappend (OneTuple x) (OneTuple y) = OneTuple (mappend x y)
+only :: OneTuple a -> a
+only = getSolo
 
-instance MonadFix OneTuple where
-    mfix f = let a = f (only a) in a
+pattern OneTuple :: a -> Solo a
+pattern OneTuple a = MkSolo a
 
+{-# COMPLETE OneTuple #-}
diff --git a/src/Data/Tuple/Solo.hs b/src/Data/Tuple/Solo.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Tuple/Solo.hs
@@ -0,0 +1,200 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE Safe #-}
+
+-- | 'Solo' fills the /tuple gap/ with a singleton tuple.
+--
+-- 'Solo' /does not support/ the usual parenthesized tuple syntax.
+--
+-- 'Solo'
+--
+--   * has the expected laziness properties
+--
+--   * can be pattern-matched
+--
+--   * ships with instances for several standard type classes,
+--     including all those supported by H98-standard tuples
+--
+--   * requires no language extensions, except for hierarchical modules
+--
+-- Note: on GHC-9.0 'getSolo' is not a record selector.
+
+module Data.Tuple.Solo (
+    Solo(MkSolo,Solo),
+    getSolo,
+) where
+
+#ifdef MIN_VERSION_base_orphans
+import Data.Orphans ()
+#endif
+
+#if MIN_VERSION_base(4,18,0)
+import GHC.Tuple (Solo (MkSolo, Solo), getSolo)
+
+
+#elif MIN_VERSION_base(4,16,0)
+import GHC.Tuple (Solo (Solo), getSolo)
+
+pattern MkSolo :: a -> Solo a
+pattern MkSolo a = Solo a
+
+{-# COMPLETE MkSolo #-}
+
+#elif MIN_VERSION_base(4,15,0)
+import GHC.Tuple (Solo (Solo))
+
+-- | The 'getSolo' function extracts the Solo's getSolo member.
+getSolo :: Solo a -> a
+getSolo (Solo x) = x
+
+pattern MkSolo :: a -> Solo a
+pattern MkSolo a = Solo a
+
+{-# COMPLETE MkSolo #-}
+
+-- !MIN_VERSION_base(4,15,0)
+#else
+
+import Control.Applicative (Applicative (..))
+import Control.Monad       (ap)
+import Control.Monad.Fix   (MonadFix (..))
+import Data.Data           (Data)
+import Data.Foldable       (Foldable (..))
+import Data.Ix             (Ix (..))
+import Data.List.NonEmpty  (NonEmpty (..))
+import Data.Monoid         (Monoid (..))
+import Data.Semigroup      (Semigroup (..))
+import Data.Traversable    (Traversable (..))
+import Data.Typeable       (Typeable)
+
+import qualified Data.Foldable1 as F1
+
+import Data.Functor.Classes (Eq1 (..), Ord1 (..), Show1 (..), Read1 (..))
+
+#if !(MIN_VERSION_base(4,15,0))
+import Data.Hashable        (Hashable (..))
+import Data.Hashable.Lifted (Hashable1 (..), hashWithSalt1)
+#endif
+
+import Data.Functor.Classes (readData, readUnaryWith, liftReadListDefault, liftReadListPrecDefault)
+import GHC.Generics        (Generic, Generic1)
+import Control.Monad.Zip   (MonadZip (..))
+
+-- | Solo is the singleton tuple data type.
+data Solo a = MkSolo { getSolo :: a }
+  deriving
+    ( Eq,Ord,Bounded,Read,Typeable,Data
+    , Generic
+    , Generic1
+    )
+
+pattern Solo :: a -> Solo a
+pattern Solo a = MkSolo a
+{-# COMPLETE Solo #-}
+
+
+instance Show a => Show (Solo a) where
+  showsPrec d (MkSolo x) = showParen (d > 10) $
+      showString "MkSolo " . showsPrec 11 x
+
+instance (Enum a) => Enum (Solo a) where
+    succ = fmap succ
+    pred = fmap pred
+    toEnum = pure . toEnum
+    fromEnum (MkSolo x) = fromEnum x
+
+instance (Ix a) => Ix (Solo a) where
+    range   (MkSolo x, MkSolo y) = map MkSolo (range (x,y))
+    index   (MkSolo x, MkSolo y) (MkSolo z) = index   (x,y) z
+    inRange (MkSolo x, MkSolo y) (MkSolo z) = inRange (x,y) z
+
+instance Foldable Solo where
+    fold (MkSolo m) = m
+    foldMap f (MkSolo x) = f x
+    foldr f b (MkSolo x) = f x b
+    foldl f a (MkSolo x) = f a x
+    foldr1 _f (MkSolo x) = x
+    foldl1 _f (MkSolo x) = x
+
+    -- TODO: add rest of the methods
+    null _ = False
+    length _ = 1
+
+    maximum = getSolo
+    minimum = getSolo
+    sum     = getSolo
+    product = getSolo
+
+    toList (MkSolo a) = [a]
+
+-- | @since 0.4
+instance F1.Foldable1 Solo where
+    foldMap1 f (MkSolo y) = f y
+    toNonEmpty (MkSolo x) = x :| []
+    minimum (MkSolo x) = x
+    maximum (MkSolo x) = x
+    head (MkSolo x) = x
+    last (MkSolo x) = x
+
+instance Traversable Solo where
+    traverse f (MkSolo x) = fmap MkSolo (f x)
+    sequenceA (MkSolo x) = fmap MkSolo x
+
+instance Functor Solo where
+    fmap f (MkSolo x) = MkSolo (f x)
+
+instance Applicative Solo where
+    pure = MkSolo
+
+    MkSolo f <*> MkSolo x = MkSolo (f x)
+    _ *> x = x
+    x <* _ = x
+
+    liftA2 f (Solo x) (Solo y) = Solo (f x y)
+
+instance Monad Solo where
+    return = pure
+    (>>) = (*>)
+    MkSolo x >>= f = f x
+
+instance Semigroup a => Semigroup (Solo a) where
+    MkSolo x <> MkSolo y = MkSolo (x <> y)
+
+instance Monoid a => Monoid (Solo a) where
+    mempty = MkSolo mempty
+    mappend (MkSolo x) (MkSolo y) = MkSolo (mappend x y)
+
+instance MonadFix Solo where
+    mfix f = let a = f (getSolo a) in a
+
+instance MonadZip Solo where
+    mzipWith f (MkSolo a) (MkSolo b) = MkSolo (f a b)
+
+instance Eq1 Solo where
+  liftEq eq (MkSolo a) (MkSolo b) = a `eq` b
+
+instance Ord1 Solo where
+  liftCompare cmp (MkSolo a) (MkSolo b) = cmp a b
+
+instance Read1 Solo where
+    liftReadPrec rp _ = readData (readUnaryWith rp "MkSolo" MkSolo)
+
+    liftReadListPrec = liftReadListPrecDefault
+    liftReadList     = liftReadListDefault
+
+instance Show1 Solo where
+    liftShowsPrec sp _ d (MkSolo x) = showParen (d > 10) $
+      showString "MkSolo " . sp 11 x
+#endif
+
+#if !(MIN_VERSION_base(4,15,0))
+-- | @since 0.3.1
+instance Hashable a => Hashable (Solo a) where
+    hashWithSalt = hashWithSalt1
+
+-- | @since 0.3.1
+instance Hashable1 Solo where
+    liftHashWithSalt h salt (MkSolo a) = h salt a
+#endif
diff --git a/src/Data/Tuple/Solo/TH.hs b/src/Data/Tuple/Solo/TH.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Tuple/Solo/TH.hs
@@ -0,0 +1,44 @@
+{-# LANGUAGE CPP #-}
+#if __GLASGOW_HASKELL__ >= 800
+{-# LANGUAGE TemplateHaskellQuotes #-}
+#endif
+-- | This module provides TH helpers,
+-- which use 'Solo' from this package, for 1-tuples.
+module Data.Tuple.Solo.TH (
+    tupE,
+) where
+
+
+#if MIN_VERSION_template_haskell(2,17,0)
+import Language.Haskell.TH (tupE)
+#else
+import Data.Tuple.Solo
+
+import qualified Language.Haskell.TH as TH
+import qualified Language.Haskell.TH.Syntax as TH
+
+makeTup :: [TH.Exp] -> TH.Exp
+makeTup [x] = TH.AppE (TH.ConE soloConName) x
+#if MIN_VERSION_template_haskell(2,16,0)
+makeTup xs  = TH.TupE (map Just xs)
+#else
+makeTup xs  = TH.TupE xs
+#endif
+
+soloConName :: TH.Name
+#if __GLASGOW_HASKELL__ >= 800
+soloConName = 'Solo
+#else
+#ifndef CURRENT_PACKAGE_KEY 
+#error "CURRENT_PACKAGE_KEY undefined"
+#endif
+
+soloConName = TH.mkNameG_d CURRENT_PACKAGE_KEY "Data.Tuple.Solo" "MkSolo"
+#endif
+
+tupE :: Monad m => [m TH.Exp] -> m TH.Exp
+tupE xs = do
+    xs' <- sequence xs
+    return (makeTup xs')
+#endif
+
diff --git a/test/instances.hs b/test/instances.hs
new file mode 100644
--- /dev/null
+++ b/test/instances.hs
@@ -0,0 +1,74 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -Wincomplete-patterns -Werror=incomplete-patterns #-}
+{-# OPTIONS_GHC -fwarn-incomplete-patterns -Werror #-}
+module Main where
+
+import Control.Applicative  (Applicative (..))
+import Control.Monad.Fix    (MonadFix (..))
+import Data.Data            (Data)
+import Data.Foldable        (Foldable (..))
+import Data.Foldable1       (Foldable1)
+import Data.Functor.Classes (Eq1, Ord1, Read1, Show1)
+import Data.Hashable        (Hashable)
+import Data.Hashable.Lifted (Hashable1)
+import Data.Ix              (Ix)
+import Data.Monoid          (Monoid (..))
+import Data.Semigroup       (Semigroup (..))
+import Data.Traversable     (Traversable (..))
+
+#if MIN_VERSION_base(4,4,0)
+import Control.Monad.Zip (MonadZip (..))
+#endif
+
+import Data.Tuple.Solo (Solo (..))
+
+main :: IO ()
+main = putStrLn "works"
+
+-------------------------------------------------------------------------------
+-- pattern match
+-------------------------------------------------------------------------------
+
+match :: Solo a -> a
+match (MkSolo x) = x
+
+-------------------------------------------------------------------------------
+-- Instances
+-------------------------------------------------------------------------------
+
+tup1 :: Solo Char
+tup1 = MkSolo 'x'
+
+tup2 :: Solo String
+tup2 = MkSolo "test"
+
+hasEq :: Eq a => a -> a; hasEq x = x; testEq = hasEq tup1
+hasOrd :: Ord a => a -> a; hasOrd x = x; testOrd = hasOrd tup1
+hasBounded :: Bounded a => a -> a; hasBounded x = x; testBounded = hasBounded tup1
+hasEnum :: Enum a => a -> a; hasEnum x = x; testEnum = hasEnum tup1
+hasShow :: Show a => a -> a; hasShow x = x; testShow = hasShow tup1
+hasRead :: Read a => a -> a; hasRead x = x; testRead = hasRead tup1
+hasIx :: Ix a => a -> a; hasIx x = x; testIx = hasIx tup1
+
+hasMonoid :: Monoid a => a -> a; hasMonoid x = x; testMonoid = hasMonoid tup2
+hasSemigroup :: Semigroup a => a -> a; hasSemigroup x = x; testSemigroup = hasSemigroup tup2
+
+hasData :: Data a => a -> a; hasData x = x; testData = hasData tup2
+
+hasFunctor :: Functor f => f a -> f a; hasFunctor x = x; testFunctor = hasFunctor tup1
+hasFoldable :: Foldable f => f a -> f a; hasFoldable x = x; testFoldable = hasFoldable tup1
+hasFoldable1 :: Foldable1 f => f a -> f a; hasFoldable1 x = x; testFoldable1 = hasFoldable1 tup1
+hasTraversable :: Traversable f => f a -> f a; hasTraversable x = x; testTraversable = hasTraversable tup1
+hasApplicative :: Applicative f => f a -> f a; hasApplicative x = x; testApplicative = hasApplicative tup1
+hasMonad :: Monad f => f a -> f a; hasMonad x = x; testMonad = hasMonad tup1
+hasMonadFix :: MonadFix f => f a -> f a; hasMonadFix x = x; testMonadFix = hasMonadFix tup1
+
+hasMonadZip :: MonadZip f => f a -> f a; hasMonadZip x = x; testMonadZip = hasMonadZip tup1
+
+hasEq1 :: Eq1 f => f a -> f a; hasEq1 x = x; testEq1 = hasEq1 tup1
+hasOrd1 :: Ord1 f => f a -> f a; hasOrd1 x = x; testOrd1 = hasOrd1 tup1
+hasShow1 :: Show1 f => f a -> f a; hasShow1 x = x; testShow1 = hasShow1 tup1
+hasRead1 :: Read1 f => f a -> f a; hasRead1 x = x; testRead1 = hasRead1 tup1
+
+hasHashable :: Hashable a => a -> a; hasHashable x = x; testHashable = hasHashable tup1
+hasHashable1 :: Hashable1 f => f a -> f a; hasHashable1 x = x; testHashable1 = hasHashable1 tup1
diff --git a/test/th.hs b/test/th.hs
new file mode 100644
--- /dev/null
+++ b/test/th.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE TemplateHaskell #-}
+module Main where
+
+import Data.Tuple.Solo
+import Data.Tuple.Solo.TH (tupE)
+
+main :: IO ()
+main = print $ MkSolo 'x' == $(tupE [[| 'x' |]])
