diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
 # Changelog
 
+## 6.0.3 (2023-10-23)
+
+#### Added
+
+- `Data` instances for the various data types.
+- Simple conversion types between the main version types.
+- Compile-time constructors via Template Haskell, like `versioningQ`.
+
 ## 6.0.2 (2023-10-12)
 
 #### Added
diff --git a/Data/Versions.hs b/Data/Versions.hs
--- a/Data/Versions.hs
+++ b/Data/Versions.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE CPP                #-}
 {-# LANGUAGE DeriveAnyClass     #-}
+{-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE DeriveGeneric      #-}
 {-# LANGUAGE DeriveLift         #-}
 {-# LANGUAGE DerivingStrategies #-}
@@ -50,6 +51,10 @@
   , Chunk(..)
   , MChunk(..)
   , VSep(..)
+    -- ** Compile-time Constructors
+  , versioningQ, semverQ, versionQ, messQ, pvpQ
+    -- ** Conversions
+  , semverToVersion, versionToMess, versionToPvp
     -- * Parsing Versions
   , ParsingError
   , versioning, semver, pvp, version, mess
@@ -76,6 +81,7 @@
 import           Control.DeepSeq
 import           Control.Monad (unless, void)
 import           Data.Char (isAlpha, isAlphaNum)
+import           Data.Data (Data)
 import           Data.Foldable (fold)
 import           Data.Hashable (Hashable)
 import           Data.List (intersperse)
@@ -86,7 +92,8 @@
 import qualified Data.Text as T
 import           Data.Void (Void)
 import           GHC.Generics (Generic)
-import           Language.Haskell.TH.Syntax (Lift)
+import           Language.Haskell.TH (Exp, Q)
+import           Language.Haskell.TH.Syntax (Lift(..))
 import           Text.Megaparsec hiding (chunk)
 import           Text.Megaparsec.Char
 import qualified Text.Megaparsec.Char.Lexer as L
@@ -99,7 +106,7 @@
 -- composed. This is useful for specifying custom behaviour for when a certain
 -- parser fails.
 data Versioning = Ideal SemVer | General Version | Complex Mess
-  deriving (Eq, Show, Generic, NFData, Hashable, Lift)
+  deriving (Eq, Show, Generic, NFData, Hashable, Lift, Data)
 
 -- | Short-hand for detecting a `SemVer`.
 isIdeal :: Versioning -> Bool
@@ -126,19 +133,19 @@
 -- and @Complex@ is well defined for the same reason. This implies comparison of
 -- @Ideal@ and @Complex@ is also well-defined.
 instance Ord Versioning where
-  compare (Ideal s)     (Ideal s')   = compare s s'
-  compare (General v)   (General v') = compare v v'
-  compare (Complex m)   (Complex m') = compare m m'
-  compare (Ideal s)     (General v)  = semverAndVer s v
-  compare (General v)   (Ideal s)    = opposite $ semverAndVer s v
-  compare (General v)   (Complex m)  = compare (mFromV v) m
-  compare (Complex m)   (General v)  = opposite $ compare (mFromV v) m
-  compare (Ideal s)     (Complex m)  = semverAndMess s m
-  compare (Complex m)   (Ideal s)    = opposite $ semverAndMess s m
+  compare (Ideal s)   (Ideal s')   = compare s s'
+  compare (General v) (General v') = compare v v'
+  compare (Complex m) (Complex m') = compare m m'
+  compare (Ideal s)   (General v)  = semverAndVer s v
+  compare (General v) (Ideal s)    = opposite $ semverAndVer s v
+  compare (General v) (Complex m)  = compare (versionToMess v) m
+  compare (Complex m) (General v)  = opposite $ compare (versionToMess v) m
+  compare (Ideal s)   (Complex m)  = semverAndMess s m
+  compare (Complex m) (Ideal s)    = opposite $ semverAndMess s m
 
 -- | Convert a `SemVer` to a `Version`.
-vFromS :: SemVer -> Version
-vFromS (SemVer ma mi pa re me) =
+semverToVersion :: SemVer -> Version
+semverToVersion (SemVer ma mi pa re me) =
   Version
   { _vEpoch = Nothing
   , _vChunks = Chunks $ Numeric ma :| [Numeric mi, Numeric pa]
@@ -146,8 +153,8 @@
   , _vRel = re }
 
 -- | Convert a `Version` to a `Mess`.
-mFromV :: Version -> Mess
-mFromV (Version me (Chunks v) r _) = case me of
+versionToMess :: Version -> Mess
+versionToMess (Version me (Chunks v) r _) = case me of
   Nothing -> f
   Just e  ->
     let cs = (:| []) . MDigit e $ showt e
@@ -163,6 +170,17 @@
       where
         ms = NEL.map toMChunk cs
 
+-- | Convert a `Version` to a `PVP`. Fails if there is an epoch present, but
+-- otherwise ignores the `Release` and other metadata. Naturally it also fails
+-- if any of the version components contain any non-digits.
+versionToPvp :: Version -> Maybe PVP
+versionToPvp (Version (Just _) _ _ _) = Nothing
+versionToPvp (Version Nothing (Chunks cs) _ _) = PVP <$> traverse f cs
+  where
+    f :: Chunk -> Maybe Word
+    f (Numeric w)  = Just w
+    f (Alphanum _) = Nothing
+
 semverAndVer :: SemVer -> Version -> Ordering
 -- A `Version` with a non-zero epoch value is automatically greater than any
 -- `SemVer`.
@@ -231,7 +249,7 @@
           EQ -> GT
   where
     fallback :: Ordering
-    fallback = compare (General $ vFromS s) (Complex m)
+    fallback = compare (General $ semverToVersion s) (Complex m)
 
 instance Semantic Versioning where
   major f (Ideal v)   = Ideal   <$> major f v
@@ -386,7 +404,7 @@
   , _svPatch  :: !Word
   , _svPreRel :: !(Maybe Release)
   , _svMeta   :: !(Maybe Text) }
-  deriving stock (Show, Generic, Lift)
+  deriving stock (Show, Generic, Lift, Data)
   deriving anyclass (NFData, Hashable)
 
 -- | Two SemVers are equal if all fields except metadata are equal.
@@ -427,7 +445,7 @@
 
 -- | `Chunk`s have comparison behaviour according to SemVer's rules for preleases.
 newtype Release = Release (NonEmpty Chunk)
-  deriving stock (Eq, Show, Read, Generic, Lift)
+  deriving stock (Eq, Show, Read, Generic, Lift, Data)
   deriving anyclass (NFData, Hashable)
 
 instance Ord Release where
@@ -459,7 +477,7 @@
 -- 0rc1-abc3
 -- @
 data Chunk = Numeric Word | Alphanum Text
-  deriving stock (Eq, Show, Read, Generic, Lift)
+  deriving stock (Eq, Show, Read, Generic, Lift, Data)
   deriving anyclass (NFData, Hashable)
 
 toMChunk :: Chunk -> MChunk
@@ -525,7 +543,7 @@
 --    change. The spec otherwise designates no special meaning to components
 --    past the MINOR position.
 newtype PVP = PVP { _pComponents :: NonEmpty Word }
-  deriving stock (Eq, Ord, Show, Generic)
+  deriving stock (Eq, Ord, Show, Generic, Lift, Data)
   deriving anyclass (NFData, Hashable)
 
 instance Semantic PVP where
@@ -577,7 +595,7 @@
   , _vChunks :: !Chunks
   , _vRel    :: !(Maybe Release)
   , _vMeta   :: !(Maybe Text) }
-  deriving stock (Eq, Show, Generic, Lift)
+  deriving stock (Eq, Show, Generic, Lift, Data)
   deriving anyclass (NFData, Hashable)
 
 -- | Customized. As in SemVer, metadata is ignored for the purpose of
@@ -620,7 +638,7 @@
   {-# INLINE meta #-}
 
   semantic f (Version _ (Chunks (Numeric a :| Numeric b : Numeric c : _)) rs me) =
-    vFromS <$> f (SemVer a b c rs me)
+    semverToVersion <$> f (SemVer a b c rs me)
   semantic _ v = pure v
   {-# INLINE semantic #-}
 
@@ -631,7 +649,7 @@
 
 -- | `Chunk`s that have a comparison behaviour specific to `Version`.
 newtype Chunks = Chunks (NonEmpty Chunk)
-  deriving stock (Eq, Show, Generic, Lift)
+  deriving stock (Eq, Show, Generic, Lift, Data)
   deriving anyclass (NFData, Hashable)
 
 instance Ord Chunks where
@@ -659,7 +677,7 @@
   -- ^ A numeric value preceeded by an @r@, indicating a revision.
   | MPlain Text
   -- ^ Anything else.
-  deriving stock (Eq, Show, Generic, Lift)
+  deriving stock (Eq, Show, Generic, Lift, Data)
   deriving anyclass (NFData, Hashable)
 
 instance Ord MChunk where
@@ -688,7 +706,7 @@
 -- internal tests show consistency. `messMajor`, etc., are used internally where
 -- appropriate to enhance accuracy.
 data Mess = Mess !(NonEmpty MChunk) !(Maybe (VSep, Mess))
-  deriving stock (Eq, Show, Generic, Lift)
+  deriving stock (Eq, Show, Generic, Lift, Data)
   deriving anyclass (NFData, Hashable)
 
 -- | Try to extract the "major" version number from `Mess`, as if it were a
@@ -750,7 +768,7 @@
 
   -- | Good luck.
   semantic f (Mess (MDigit t0 _ :| MDigit t1 _ : MDigit t2 _ : _) _) =
-    mFromV . vFromS <$> f (SemVer t0 t1 t2 Nothing Nothing)
+    versionToMess . semverToVersion <$> f (SemVer t0 t1 t2 Nothing Nothing)
   semantic _ v = pure v
   {-# INLINE semantic #-}
 
@@ -763,8 +781,43 @@
 -- * A plus (+). Stop using this outside of metadata if you are. Example: @10.2+0.93+1-1@
 -- * An underscore (_). Stop using this if you are.
 data VSep = VColon | VHyphen | VPlus | VUnder | VTilde
-  deriving stock (Eq, Show, Generic, Lift)
+  deriving stock (Eq, Show, Generic, Lift, Data)
   deriving anyclass (NFData, Hashable)
+
+-- | Parse a `Versioning` at compile time.
+versioningQ :: Text -> Q Exp
+versioningQ nm =
+  case versioning nm of
+    Left err -> fail (errorBundlePretty err)
+    Right v  -> lift v
+
+-- | Parse a `SemVer` at compile time.
+semverQ :: T.Text -> Q Exp
+semverQ nm =
+  case semver nm of
+    Left err -> fail (errorBundlePretty err)
+    Right v  -> lift v
+
+-- | Parse a `Version` at compile time.
+versionQ :: T.Text -> Q Exp
+versionQ nm =
+  case version nm of
+    Left err -> fail (errorBundlePretty err)
+    Right v  -> lift v
+
+-- | Parse a `Mess` at compile time.
+messQ :: T.Text -> Q Exp
+messQ nm =
+  case mess nm of
+    Left err -> fail (errorBundlePretty err)
+    Right v  -> lift v
+
+-- | Parse a `PVP` at compile time.
+pvpQ :: T.Text -> Q Exp
+pvpQ nm =
+  case pvp nm of
+    Left err -> fail (errorBundlePretty err)
+    Right v  -> lift v
 
 --------------------------------------------------------------------------------
 -- Parsing
diff --git a/test/TH.hs b/test/TH.hs
deleted file mode 100644
--- a/test/TH.hs
+++ /dev/null
@@ -1,19 +0,0 @@
--- | Template Haskell seems picky about compilation stages. The code here must
--- be defined in a module separate from the one it's being used in.
-
-module TH (thVer) where
-
-import qualified Data.Text as T
-import           Data.Versions
-import           Language.Haskell.TH (Exp, Q)
-import           Language.Haskell.TH.Syntax (lift)
-
----
-
--- | Parse a `Versioning` at compile time.
-thVer :: T.Text -> Q Exp
-thVer nm =
-  case versioning nm of
-    Left err -> fail (errorBundlePretty err)
-    Right v  -> lift v
-
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -18,7 +18,6 @@
 import           Text.Megaparsec
 import           Text.Megaparsec.Char
 import           Text.Printf (printf)
-import           TH (thVer)
 
 ---
 
@@ -178,6 +177,10 @@
         , eqVer "1.0.r15.g3fc772c-5"
         , eqVer "0.88-2"
         ]
+      , testGroup "Conversions"
+        [ testCase "Good Version -> PVP" $ versionToPvp $(versionQ "1.2.3") @?= Just $(pvpQ "1.2.3")
+        , testCase "Bad  Version -> PVP" $ versionToPvp $(versionQ "1.e.3") @?= Nothing
+        ]
       ]
     , testGroup "Lenses and Traversals"
       [ testCase "SemVer - Increment Patch" incPatch
@@ -185,14 +188,15 @@
       , testCase "SemVer - Get patches" patches
       ]
     , testGroup "Template Haskell"
-      [ testCase "SemVer"  $ prettyV $(thVer "1.2.3") @?= "1.2.3"
-      , testCase "Version" $ prettyV $(thVer "1.2.3.4") @?= "1.2.3.4"
-      , testCase "Mess"    $ prettyV $(thVer "003.03-3") @?= "003.03-3"
-      , testCase "Failure" $ $(recover [| () |] (thVer "!!!")) @?= ()
+      [ testCase "SemVer"  $ prettyV $(versioningQ "1.2.3") @?= "1.2.3"
+      , testCase "Version" $ prettyV $(versioningQ "1.2.3.4") @?= "1.2.3.4"
+      , testCase "Mess"    $ prettyV $(versioningQ "003.03-3") @?= "003.03-3"
+      , testCase "Failure" $ $(recover [| () |] (versioningQ "!!!")) @?= ()
       ]
     , testGroup "Megaparsec Behaviour"
       [ testCase "manyTill" $ parse nameGrab "manyTill" "linux-firmware-3.2.14-1-x86_64.pkg.tar.xz" @?= Right "linux-firmware"
       , testCase "Extracting version" $ parse versionGrab "extraction" "linux-firmware-3.2.14-1-x86_64.pkg.tar.xz" @?= Right (Ideal $ SemVer 3 2 14 (Just . Release $ Alphanum "1-x86" :| []) Nothing)
+      , testCase "Parser State" $ parse pvp'' "parser state" "1.2.3arst" @?= Right ($(pvpQ "1.2.3"), "arst")
       ]
     ]
   ]
@@ -279,3 +283,10 @@
 hush :: Either a b -> Maybe b
 hush (Left _)  = Nothing
 hush (Right b) = Just b
+
+-- | An attempt to squeeze out the remaining parser state.
+pvp'' :: Parsec Void T.Text (PVP, T.Text)
+pvp'' = do
+  v <- pvp'
+  s <- getParserState
+  pure (v, stateInput s)
diff --git a/versions.cabal b/versions.cabal
--- a/versions.cabal
+++ b/versions.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.2
 name:               versions
-version:            6.0.2
+version:            6.0.3
 synopsis:           Types and parsers for software version numbers.
 description:
   A library for parsing and comparing software version numbers. We like to give
@@ -59,7 +59,6 @@
   main-is:        Test.hs
   hs-source-dirs: test
   ghc-options:    -threaded -with-rtsopts=-N
-  other-modules:  TH
   build-depends:
     , microlens         >=0.4
     , tasty             >=0.10.1.2
