diff --git a/README.markdown b/README.markdown
new file mode 100644
--- /dev/null
+++ b/README.markdown
@@ -0,0 +1,8 @@
+# Salve
+
+[![Build badge][]][build status]
+
+Salve provides semantic version numbers and constraints for Haskell.
+
+[Build badge]: https://travis-ci.org/tfausak/salve.svg?branch=master
+[build status]: https://travis-ci.org/tfausak/salve
diff --git a/benchmarks/benchmark.hs b/benchmarks/benchmark.hs
--- a/benchmarks/benchmark.hs
+++ b/benchmarks/benchmark.hs
@@ -4,43 +4,67 @@
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE StandaloneDeriving #-}
 
-import Control.DeepSeq
-import Criterion.Main
-import GHC.Generics
-import Salve.Internal
+import qualified Control.DeepSeq as DeepSeq
+import qualified Criterion.Main as Criterion
+import qualified Data.Maybe as Maybe
+import qualified Data.Version as Version
+import qualified GHC.Generics as Ghc
+import qualified Salve.Internal as Salve
+import qualified Text.ParserCombinators.ReadP as ReadP
 
-deriving instance Generic Build
-deriving instance Generic Constraint
-deriving instance Generic Operator
-deriving instance Generic PreRelease
-deriving instance Generic Version
+deriving instance Ghc.Generic Salve.Build
+deriving instance Ghc.Generic Salve.Constraint
+deriving instance Ghc.Generic Salve.Operator
+deriving instance Ghc.Generic Salve.PreRelease
+deriving instance Ghc.Generic Salve.Version
 
-deriving instance NFData Build
-deriving instance NFData Constraint
-deriving instance NFData Operator
-deriving instance NFData PreRelease
-deriving instance NFData Version
+deriving instance DeepSeq.NFData Salve.Build
+deriving instance DeepSeq.NFData Salve.Constraint
+deriving instance DeepSeq.NFData Salve.Operator
+deriving instance DeepSeq.NFData Salve.PreRelease
+deriving instance DeepSeq.NFData Salve.Version
 
 main :: IO ()
-main = defaultMain
-  [ bgroup "parseVersion" (map
-    (\ x -> bench x (nf parseVersion x))
+main = Criterion.defaultMain
+  [ Criterion.bgroup "Data.Version.parseVersion" (map
+    (\ x -> Criterion.bench x (Criterion.nf (runReadP Version.parseVersion) x))
     [ "0.0.0"
+    , "123.456.789-pre-release-build-metadata"
+    ])
+  , Criterion.bgroup "parseVersion" (map
+    (\ x -> Criterion.bench x (Criterion.nf Salve.parseVersion x))
+    [ "0.0.0"
     , "123.456.789-pre.release+build.metadata"
     ])
-  , bgroup "parseConstraint" (map
-    (\ x -> bench x (nf parseConstraint x))
+  , Criterion.bgroup "parseConstraint" (map
+    (\ x -> Criterion.bench x (Criterion.nf Salve.parseConstraint x))
     [ ">=0.0.0"
-    , ">1.2.3 || =1.2.3 >=1.2.3 <1.2.3 || 1.2.3 <=1.2.3 ~1.2.3 ^1.2.3"
+    , ">1.2.3 || =1.2.3 >=1.2.3 <1.2.3 || 1.2.3 <=1.2.3 ~1.2.3 ^1.2.3 1.2.3 - 1.2.3"
     ])
-  , bgroup "renderVersion" (map
-    (\ x -> let y = unsafeParseVersion x in bench x (nf renderVersion y))
+  , Criterion.bgroup "Data.Version.showVersion" (map
+    (\ x ->
+      let y = Maybe.fromJust (runReadP Version.parseVersion x)
+      in Criterion.bench x (Criterion.nf Version.showVersion y))
     [ "0.0.0"
+    , "123.456.789-pre-release-build-metadata"
+    ])
+  , Criterion.bgroup "renderVersion" (map
+    (\ x ->
+      let y = Salve.unsafeParseVersion x
+      in Criterion.bench x (Criterion.nf Salve.renderVersion y))
+    [ "0.0.0"
     , "123.456.789-pre.release+build.metadata"
     ])
-  , bgroup "renderConstraint" (map
-    (\ x -> let y = unsafeParseConstraint x in bench x (nf renderConstraint y))
+  , Criterion.bgroup "renderConstraint" (map
+    (\ x ->
+      let y = Salve.unsafeParseConstraint x
+      in Criterion.bench x (Criterion.nf Salve.renderConstraint y))
     [ ">=0.0.0"
     , ">1.2.3 || =1.2.3 >=1.2.3 <1.2.3 || 1.2.3 <=1.2.3 ~1.2.3 ^1.2.3"
     ])
   ]
+
+runReadP :: ReadP.ReadP a -> String -> Maybe a
+runReadP parser string = Maybe.listToMaybe (do
+  (x, "") <- ReadP.readP_to_S parser string
+  pure x)
diff --git a/library/Salve.hs b/library/Salve.hs
--- a/library/Salve.hs
+++ b/library/Salve.hs
@@ -8,6 +8,9 @@
 --
 -- >>> import Salve
 --
+-- This module provides lenses for modifying versions. If you want to modify
+-- versions, consider importing a lens library like "Lens.Micro".
+--
 -- The 'Version' data type is the core of this module. Use 'parseVersion' to
 -- make versions and 'renderVersion' to convert them into strings.
 --
@@ -25,12 +28,139 @@
 --
 -- >>> satisfies <$> parseVersion "1.2.3" <*> parseConstraint ">1.2.0"
 -- Just True
+--
+-- == __Examples__
+--
+-- === Versions
+--
+-- No leading zeros.
+--
+-- >>> parseVersion "01.0.0"
+-- Nothing
+-- >>> parseVersion "0.01.0"
+-- Nothing
+-- >>> parseVersion "0.0.01"
+-- Nothing
+--
+-- No negative numbers.
+--
+-- >>> parseVersion "-1.0.0"
+-- Nothing
+-- >>> parseVersion "0.-1.0"
+-- Nothing
+-- >>> parseVersion "0.0.-1"
+-- Nothing
+--
+-- No non-digits.
+--
+-- >>> parseVersion "a.0.0"
+-- Nothing
+-- >>> parseVersion "0.a.0"
+-- Nothing
+-- >>> parseVersion "0.0.a"
+-- Nothing
+--
+-- No partial version numbers.
+--
+-- >>> parseVersion "0.0"
+-- Nothing
+--
+-- No extra version numbers.
+--
+-- >>> parseVersion "0.0.0.0"
+-- Nothing
+--
+-- === Constraints
+--
+-- No partial version numbers.
+--
+-- >>> parseConstraint "1.2"
+-- Nothing
+--
+-- No wildcards.
+--
+-- >>> parseConstraint "1.2.x"
+-- Nothing
+-- >>> parseConstraint "1.2.X"
+-- Nothing
+-- >>> parseConstraint "1.2.*"
+-- Nothing
+--
+-- Round-tripping.
+--
+-- >>> renderConstraint <$> parseConstraint "<=1.2.3"
+-- Just "<=1.2.3"
+-- >>> renderConstraint <$> parseConstraint "<1.2.3"
+-- Just "<1.2.3"
+-- >>> renderConstraint <$> parseConstraint "=1.2.3"
+-- Just "1.2.3"
+-- >>> renderConstraint <$> parseConstraint ">=1.2.3"
+-- Just ">=1.2.3"
+-- >>> renderConstraint <$> parseConstraint ">1.2.3"
+-- Just ">1.2.3"
+-- >>> renderConstraint <$> parseConstraint ">1.2.3 <2.0.0"
+-- Just ">1.2.3 <2.0.0"
+-- >>> renderConstraint <$> parseConstraint "1.2.3 || >1.2.3"
+-- Just "1.2.3 || >1.2.3"
+--
+-- Implicit equals.
+--
+-- >>> renderConstraint <$> parseConstraint "1.2.3"
+-- Just "1.2.3"
+--
+-- Hyphens.
+--
+-- >>> renderConstraint <$> parseConstraint "1.2.3 - 2.3.4"
+-- Just ">=1.2.3 <=2.3.4"
+--
+-- Tildes.
+--
+-- >>> renderConstraint <$> parseConstraint "~1.2.3"
+-- Just ">=1.2.3 <1.3.0"
+-- >>> renderConstraint <$> parseConstraint "~1.2.0"
+-- Just ">=1.2.0 <1.3.0"
+-- >>> renderConstraint <$> parseConstraint "~1.0.0"
+-- Just ">=1.0.0 <1.1.0"
+--
+-- Carets.
+--
+-- >>> renderConstraint <$> parseConstraint "^1.2.3"
+-- Just ">=1.2.3 <2.0.0"
+-- >>> renderConstraint <$> parseConstraint "^0.2.3"
+-- Just ">=0.2.3 <0.3.0"
+-- >>> renderConstraint <$> parseConstraint "^0.0.3"
+-- Just ">=0.0.3 <0.0.4"
+--
+-- Pre-releases and builds.
+--
+-- >>> renderConstraint <$> parseConstraint "1.2.3-p+b"
+-- Just "1.2.3-p+b"
+-- >>> renderConstraint <$> parseConstraint "1.2.3-p+b - 2.3.4-p+b"
+-- Just ">=1.2.3-p+b <=2.3.4-p+b"
+-- >>> renderConstraint <$> parseConstraint "~1.2.3-p+b"
+-- Just ">=1.2.3-p+b <1.3.0"
+-- >>> renderConstraint <$> parseConstraint "^1.2.3-p+b"
+-- Just ">=1.2.3-p+b <2.0.0"
 
 -- * Types
 Version,
 PreRelease,
 Build,
 Constraint,
+
+-- * Constructors
+makeVersion,
+initialVersion,
+constraintLT,
+constraintLE,
+constraintEQ,
+constraintGE,
+constraintGT,
+constraintAnd,
+constraintOr,
+constraintHyphen,
+constraintTilde,
+constraintCaret,
 
 -- * Parsing
 parseVersion,
diff --git a/library/Salve/Internal.hs b/library/Salve/Internal.hs
--- a/library/Salve/Internal.hs
+++ b/library/Salve/Internal.hs
@@ -4,6 +4,7 @@
 module Salve.Internal where
 
 -- $setup
+-- >>> import Lens.Micro
 -- >>> import Lens.Micro.Extras
 
 -- * Public
@@ -130,6 +131,130 @@
   | ConstraintOr Constraint Constraint
   deriving (Eq, Show)
 
+-- | Makes a new version number.
+--
+-- >>> makeVersion 0 0 0 [] []
+-- Version {versionMajor = 0, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []}
+--
+-- This can be a useful alternative to 'parseVersion' if you want a total way
+-- to create a version.
+makeVersion :: Word -> Word -> Word -> [PreRelease] -> [Build] -> Version
+makeVersion major minor patch preReleases builds = Version
+  { versionMajor = major
+  , versionMinor = minor
+  , versionPatch = patch
+  , versionPreReleases = preReleases
+  , versionBuilds = builds
+  }
+
+-- | The initial version number for development.
+--
+-- >>> initialVersion
+-- Version {versionMajor = 0, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []}
+initialVersion :: Version
+initialVersion = makeVersion 0 0 0 [] []
+
+-- | Makes a new constraint that must be less than the version number.
+--
+-- >>> constraintLT <$> parseVersion "1.2.3"
+-- Just (ConstraintCompare OperatorLT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))
+-- >>> parseConstraint "<1.2.3"
+-- Just (ConstraintCompare OperatorLT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))
+constraintLT :: Version -> Constraint
+constraintLT v = ConstraintCompare OperatorLT v
+
+-- | Makes a new constraint that must be less than or euqal to the version
+-- number.
+--
+-- >>> constraintLE <$> parseVersion "1.2.3"
+-- Just (ConstraintCompare OperatorLE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))
+-- >>> parseConstraint "<=1.2.3"
+-- Just (ConstraintCompare OperatorLE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))
+constraintLE :: Version -> Constraint
+constraintLE v = ConstraintCompare OperatorLE v
+
+-- | Makes a new constraint that must be equal to the version number.
+--
+-- >>> constraintEQ <$> parseVersion "1.2.3"
+-- Just (ConstraintCompare OperatorEQ (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))
+-- >>> parseConstraint "=1.2.3"
+-- Just (ConstraintCompare OperatorEQ (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))
+constraintEQ :: Version -> Constraint
+constraintEQ v = ConstraintCompare OperatorEQ v
+
+-- | Makes a new constraint that must be greater than or equal to the version
+-- number.
+--
+-- >>> constraintGE <$> parseVersion "1.2.3"
+-- Just (ConstraintCompare OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))
+-- >>> parseConstraint ">=1.2.3"
+-- Just (ConstraintCompare OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))
+constraintGE :: Version -> Constraint
+constraintGE v = ConstraintCompare OperatorGE v
+
+-- | Makes a new constraint that must be greater than the version number.
+--
+-- >>> constraintGT <$> parseVersion "1.2.3"
+-- Just (ConstraintCompare OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))
+-- >>> parseConstraint ">1.2.3"
+-- Just (ConstraintCompare OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []}))
+constraintGT :: Version -> Constraint
+constraintGT v = ConstraintCompare OperatorGT v
+
+-- | Makes a new constraint that must satisfy both constraints.
+--
+-- >>> constraintAnd <$> (constraintGE <$> parseVersion "1.2.3") <*> (constraintLT <$> parseVersion "2.0.0")
+-- Just (ConstraintAnd (ConstraintCompare OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintCompare OperatorLT (Version {versionMajor = 2, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})))
+-- >>> parseConstraint ">=1.2.3 <2.0.0"
+-- Just (ConstraintAnd (ConstraintCompare OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintCompare OperatorLT (Version {versionMajor = 2, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})))
+constraintAnd :: Constraint -> Constraint -> Constraint
+constraintAnd l r = ConstraintAnd l r
+
+-- | Makes a new constraint that must satisfy either constraint.
+--
+-- >>> constraintOr <$> (constraintEQ <$> parseVersion "1.2.3") <*> (constraintGT <$> parseVersion "1.2.3")
+-- Just (ConstraintOr (ConstraintCompare OperatorEQ (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintCompare OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})))
+-- >>> parseConstraint "=1.2.3 || >1.2.3"
+-- Just (ConstraintOr (ConstraintCompare OperatorEQ (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintCompare OperatorGT (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})))
+constraintOr :: Constraint -> Constraint -> Constraint
+constraintOr l r = ConstraintOr l r
+
+-- | Makes a new constraint that must be between the versions, inclusive.
+--
+-- >>> constraintHyphen <$> parseVersion "1.2.3" <*> parseVersion "2.3.4"
+-- Just (ConstraintAnd (ConstraintCompare OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintCompare OperatorLE (Version {versionMajor = 2, versionMinor = 3, versionPatch = 4, versionPreReleases = [], versionBuilds = []})))
+-- >>> parseConstraint "1.2.3 - 2.3.4"
+-- Just (ConstraintAnd (ConstraintCompare OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintCompare OperatorLE (Version {versionMajor = 2, versionMinor = 3, versionPatch = 4, versionPreReleases = [], versionBuilds = []})))
+constraintHyphen :: Version -> Version -> Constraint
+constraintHyphen v w = constraintAnd (constraintGE v) (constraintLE w)
+
+-- | Makes a new constraint that allows changes to the patch version number.
+--
+-- >>> constraintTilde <$> parseVersion "1.2.3"
+-- Just (ConstraintAnd (ConstraintCompare OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintCompare OperatorLT (Version {versionMajor = 1, versionMinor = 3, versionPatch = 0, versionPreReleases = [], versionBuilds = []})))
+-- >>> parseConstraint "~1.2.3"
+-- Just (ConstraintAnd (ConstraintCompare OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintCompare OperatorLT (Version {versionMajor = 1, versionMinor = 3, versionPatch = 0, versionPreReleases = [], versionBuilds = []})))
+constraintTilde :: Version -> Constraint
+constraintTilde v = constraintAnd
+  (constraintGE v)
+  (constraintLT (makeVersion (versionMajor v) (versionMinor v + 1) 0 [] []))
+
+-- | Makes a new constraint that allows changes that do not modify the
+-- left-most non-zero version number.
+--
+-- >>> constraintCaret <$> parseVersion "1.2.3"
+-- Just (ConstraintAnd (ConstraintCompare OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintCompare OperatorLT (Version {versionMajor = 2, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})))
+-- >>> parseConstraint "^1.2.3"
+-- Just (ConstraintAnd (ConstraintCompare OperatorGE (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})) (ConstraintCompare OperatorLT (Version {versionMajor = 2, versionMinor = 0, versionPatch = 0, versionPreReleases = [], versionBuilds = []})))
+constraintCaret :: Version -> Constraint
+constraintCaret v = constraintAnd
+  (constraintGE v)
+  (constraintLT (if versionMajor v == 0
+    then if versionMinor v == 0
+      then makeVersion (versionMajor v) (versionMinor v) (versionPatch v + 1) [] []
+      else makeVersion (versionMajor v) (versionMinor v + 1) 0 [] []
+    else makeVersion (versionMajor v + 1) 0 0 [] []))
+
 -- | Attempts to parse a version. This parser follows [SemVer's
 -- BNF](https://github.com/mojombo/semver/blob/eb9aac5/semver.md#backusnaur-form-grammar-for-valid-semver-versions).
 --
@@ -209,13 +334,13 @@
 -- Raises an exception if the parse fails.
 --
 -- >>> unsafeParseVersion "wrong"
--- *** Exception: invalid version: "wrong"
+-- *** Exception: unsafeParseVersion: invalid version: "wrong"
 -- ...
 --
 -- See 'parseVersion' for a safe version of this function.
 unsafeParseVersion :: String -> Version
 unsafeParseVersion s = case parseVersion s of
-  Nothing -> error ("invalid version: " ++ show s)
+  Nothing -> error ("unsafeParseVersion: invalid version: " ++ show s)
   Just v -> v
 
 -- | Parses a pre-release.
@@ -226,13 +351,13 @@
 -- Raises an exception if the parse fails.
 --
 -- >>> unsafeParsePreRelease "wrong!"
--- *** Exception: invalid pre-release: "wrong!"
+-- *** Exception: unsafeParsePreRelease: invalid pre-release: "wrong!"
 -- ...
 --
 -- See 'parsePreRelease' for a safe version of this function.
 unsafeParsePreRelease :: String -> PreRelease
 unsafeParsePreRelease s = case parsePreRelease s of
-  Nothing -> error ("invalid pre-release: " ++ show s)
+  Nothing -> error ("unsafeParsePreRelease: invalid pre-release: " ++ show s)
   Just p -> p
 
 -- | Parses a build.
@@ -243,13 +368,13 @@
 -- Raises an exception if the parse fails.
 --
 -- >>> unsafeParseBuild "wrong!"
--- Build "*** Exception: invalid build: "wrong!"
+-- Build "*** Exception: unsafeParseBuild: invalid build: "wrong!"
 -- ...
 --
 -- See 'parseBuild' for a safe version of this function.
 unsafeParseBuild :: String -> Build
 unsafeParseBuild s = case parseBuild s of
-  Nothing -> error ("invalid build: " ++ show s)
+  Nothing -> error ("unsafeParseBuild: invalid build: " ++ show s)
   Just b -> b
 
 -- | Parses a constraint.
@@ -260,13 +385,13 @@
 -- Raises an exception if the parse fails.
 --
 -- >>> unsafeParseConstraint "wrong"
--- *** Exception: invalid constraint: "wrong"
+-- *** Exception: unsafeParseConstraint: invalid constraint: "wrong"
 -- ...
 --
 -- See 'parseConstraint' for a safe version of this function.
 unsafeParseConstraint :: String -> Constraint
 unsafeParseConstraint s = case parseConstraint s of
-  Nothing -> error ("invalid constraint: " ++ show s)
+  Nothing -> error ("unsafeParseConstraint: invalid constraint: " ++ show s)
   Just c -> c
 
 -- | Renders a version.
@@ -363,13 +488,7 @@
 -- Consider using 'majorLens' if you want to arbitrarily change the major
 -- number, or if you don't want the other parts of the version to change.
 bumpMajor :: Version -> Version
-bumpMajor v = v
-  { versionMajor = versionMajor v + 1
-  , versionMinor = 0
-  , versionPatch = 0
-  , versionPreReleases = []
-  , versionBuilds = []
-  }
+bumpMajor v = makeVersion (versionMajor v + 1) 0 0 [] []
 
 -- | Increments the minor version number.
 --
@@ -389,12 +508,7 @@
 -- Consider using 'minorLens' if you want to arbitrarily change the minor
 -- number, or if you don't want the other parts of the version to change.
 bumpMinor :: Version -> Version
-bumpMinor v = v
-  { versionMinor = versionMinor v + 1
-  , versionPatch = 0
-  , versionPreReleases = []
-  , versionBuilds = []
-  }
+bumpMinor v = makeVersion (versionMajor v) (versionMinor v + 1) 0 [] []
 
 -- | Increments the patch number.
 --
@@ -414,11 +528,8 @@
 -- Consider using 'patchLens' if you want to arbitrarily change the patch
 -- number, or if you don't want the other parts of the version to change.
 bumpPatch :: Version -> Version
-bumpPatch v = v
-  { versionPatch = versionPatch v + 1
-  , versionPreReleases = []
-  , versionBuilds = []
-  }
+bumpPatch v = makeVersion
+  (versionMajor v) (versionMinor v) (versionPatch v + 1) [] []
 
 -- | Returns 'True' if the version satisfies the constraint, 'False' otherwise.
 --
@@ -439,6 +550,8 @@
 --
 -- >>> view majorLens <$> parseVersion "1.2.3-pre.4+build.5"
 -- Just 1
+-- >>> set majorLens 4 <$> parseVersion "1.2.3"
+-- Just (Version {versionMajor = 4, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})
 majorLens :: Functor f => (Word -> f Word) -> Version -> f Version
 majorLens f v = fmap
   (\ m -> v { versionMajor = m })
@@ -448,6 +561,8 @@
 --
 -- >>> view minorLens <$> parseVersion "1.2.3-pre.4+build.5"
 -- Just 2
+-- >>> set minorLens 4 <$> parseVersion "1.2.3"
+-- Just (Version {versionMajor = 1, versionMinor = 4, versionPatch = 3, versionPreReleases = [], versionBuilds = []})
 minorLens :: Functor f => (Word -> f Word) -> Version -> f Version
 minorLens f v = fmap
   (\ n -> v { versionMinor = n })
@@ -457,6 +572,8 @@
 --
 -- >>> view patchLens <$> parseVersion "1.2.3-pre.4+build.5"
 -- Just 3
+-- >>> set patchLens 4 <$> parseVersion "1.2.3"
+-- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 4, versionPreReleases = [], versionBuilds = []})
 patchLens :: Functor f => (Word -> f Word) -> Version -> f Version
 patchLens f v = fmap
   (\ p -> v { versionPatch = p })
@@ -466,6 +583,8 @@
 --
 -- >>> view preReleasesLens <$> parseVersion "1.2.3-pre.4+build.5"
 -- Just [PreReleaseTextual "pre",PreReleaseNumeric 4]
+-- >>> set preReleasesLens [] <$> parseVersion "1.2.3-pre"
+-- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})
 preReleasesLens :: Functor f => ([PreRelease] -> f [PreRelease]) -> Version -> f Version
 preReleasesLens f v = fmap
   (\ ps -> v { versionPreReleases = ps })
@@ -475,6 +594,8 @@
 --
 -- >>> view buildsLens <$> parseVersion "1.2.3-pre.4+build.5"
 -- Just [Build "build",Build "5"]
+-- >>> set buildsLens [] <$> parseVersion "1.2.3+build"
+-- Just (Version {versionMajor = 1, versionMinor = 2, versionPatch = 3, versionPreReleases = [], versionBuilds = []})
 buildsLens :: Functor f => ([Build] -> f [Build]) -> Version -> f Version
 buildsLens f v = fmap
   (\ bs -> v { versionBuilds = bs })
@@ -492,27 +613,6 @@
   | OperatorGT
   deriving (Eq, Show)
 
-constraintLT :: Version -> Constraint
-constraintLT v = ConstraintCompare OperatorLT v
-
-constraintLE :: Version -> Constraint
-constraintLE v = ConstraintCompare OperatorLE v
-
-constraintEQ :: Version -> Constraint
-constraintEQ v = ConstraintCompare OperatorEQ v
-
-constraintGE :: Version -> Constraint
-constraintGE v = ConstraintCompare OperatorGE v
-
-constraintGT :: Version -> Constraint
-constraintGT v = ConstraintCompare OperatorGT v
-
-constraintAnd :: Constraint -> Constraint -> Constraint
-constraintAnd l r = ConstraintAnd l r
-
-constraintOr :: Constraint -> Constraint -> Constraint
-constraintOr l r = ConstraintOr l r
-
 -- ** Parsing
 
 versionP :: Parser Version
@@ -524,13 +624,7 @@
   patch <- numberP
   preReleases <- preReleasesP
   builds <- buildsP
-  pure Version
-    { versionMajor = major
-    , versionMinor = minor
-    , versionPatch = patch
-    , versionPreReleases = preReleases
-    , versionBuilds = builds
-    }
+  pure (makeVersion major minor patch preReleases builds)
 
 preReleasesP :: Parser [PreRelease]
 preReleasesP = optionP [] (do
@@ -591,7 +685,7 @@
   v <- versionP
   _ <- hyphenP
   w <- versionP
-  pure (constraintAnd (constraintGE v) (constraintLE w))
+  pure (constraintHyphen v w)
 
 simplesP :: Parser Constraint
 simplesP = do
@@ -605,26 +699,13 @@
 caretP = do
   _ <- charP '^'
   v <- versionP
-  let w = caretUpper v
-  pure (constraintAnd (constraintGE v) (constraintLT w))
-
-caretUpper :: Version -> Version
-caretUpper v =
-  if versionMinor v == 0
-  then bumpPatch v
-  else if versionMajor v == 0
-  then bumpMinor v
-  else bumpMajor v
+  pure (constraintCaret v)
 
 tildeP :: Parser Constraint
 tildeP = do
   _ <- charP '~'
   v <- versionP
-  let w = tildeUpper v
-  pure (constraintAnd (constraintGE v) (constraintLT w))
-
-tildeUpper :: Version -> Version
-tildeUpper v = bumpMinor v
+  pure (constraintTilde v)
 
 primitiveP :: Parser Constraint
 primitiveP = do
diff --git a/salve.cabal b/salve.cabal
--- a/salve.cabal
+++ b/salve.cabal
@@ -3,7 +3,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           salve
-version:        0.0.0
+version:        0.0.1
 synopsis:       Semantic version numbers and constraints.
 description:    Salve provides semantic version numbers and constraints.
 category:       Distribution
@@ -15,6 +15,7 @@
 
 extra-source-files:
     CHANGELOG.markdown
+    README.markdown
 
 library
   hs-source-dirs:
