diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,4 @@
+# Change log
+
+Argo follows the [Package Versioning Policy](https://pvp.haskell.org). You can
+find release notes [on GitHub](https://github.com/tfausak/argo/releases).
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+# Argo
+
+[![CI](https://github.com/tfausak/argo/actions/workflows/ci.yaml/badge.svg)](https://github.com/tfausak/argo/actions/workflows/ci.yaml)
+[![Hackage](https://img.shields.io/hackage/v/argo)](https://hackage.haskell.org/package/argo)
+
+:sailboat: Parse and render JSON.
diff --git a/argo.cabal b/argo.cabal
--- a/argo.cabal
+++ b/argo.cabal
@@ -1,11 +1,12 @@
 cabal-version: 2.2
 
 name: argo
-version: 0.2021.10.18
+version: 0.2021.10.19
 
 build-type: Simple
 category: JSON
 description: Argo parses and renders JSON.
+extra-source-files: CHANGELOG.md README.md
 license-file: LICENSE.txt
 license: MIT
 maintainer: Taylor Fausak
diff --git a/source/library/Argo.hs b/source/library/Argo.hs
--- a/source/library/Argo.hs
+++ b/source/library/Argo.hs
@@ -1,17 +1,17 @@
 {-# LANGUAGE PatternSynonyms #-}
 
 module Argo
-    ( Type.Value
+    ( Value.Value
+        ( Pattern.Null
+        , Pattern.Boolean
+        , Pattern.Number
+        , Pattern.String
+        , Pattern.Array
+        , Pattern.Object
+        )
     , Type.Array
-    , Type.Pair
+    , Pair.Pair(Pattern.Pair)
     , Type.Object
-    , pattern Pattern.Null
-    , pattern Pattern.Boolean
-    , pattern Pattern.Number
-    , pattern Pattern.String
-    , pattern Pattern.Array
-    , pattern Pattern.Object
-    , pattern Pattern.Pair
     , Encode.encode
     , Decode.decode
     , FromValue.FromValue(fromValue)
@@ -28,3 +28,5 @@
 import qualified Argo.QuasiQuoter as QuasiQuoter
 import qualified Argo.Result as Result
 import qualified Argo.Type as Type
+import qualified Argo.Type.Pair as Pair
+import qualified Argo.Type.Value as Value
diff --git a/source/library/Argo/Class/FromValue.hs b/source/library/Argo/Class/FromValue.hs
--- a/source/library/Argo/Class/FromValue.hs
+++ b/source/library/Argo/Class/FromValue.hs
@@ -3,7 +3,6 @@
 module Argo.Class.FromValue where
 
 import qualified Argo.Result as Result
-import qualified Argo.Type as Type
 import qualified Argo.Type.Array as Array
 import qualified Argo.Type.Boolean as Boolean
 import qualified Argo.Type.Number as Number
@@ -21,9 +20,9 @@
 import qualified Data.Word as Word
 
 class FromValue a where
-    fromValue :: Type.Value -> Result.Result a
+    fromValue :: Value.Value -> Result.Result a
 
-instance FromValue Type.Value where
+instance FromValue Value.Value where
     fromValue = Result.Success
 
 instance FromValue Bool where
@@ -94,7 +93,7 @@
 
 instance FromValue () where
     fromValue x = do
-        [] <- fromValue x :: Result.Result [Type.Value]
+        [] <- fromValue x :: Result.Result [Value.Value]
         pure ()
 
 instance (FromValue a, FromValue b) => FromValue (a, b) where
@@ -125,32 +124,32 @@
         . traverse (\ (Pair.Pair (String.String k, v)) -> (,) k <$> fromValue v)
         . Data.Array.elems
 
-withBoolean :: String -> (Bool -> Result.Result a) -> Type.Value -> Result.Result a
+withBoolean :: String -> (Bool -> Result.Result a) -> Value.Value -> Result.Result a
 withBoolean s f x = case x of
     Value.Boolean (Boolean.Boolean y) -> f y
     _ -> fail $ "expected " <> s <> " but got " <> show x
 
-withNumber :: String -> (Integer -> Integer -> Result.Result a) -> Type.Value -> Result.Result a
+withNumber :: String -> (Integer -> Integer -> Result.Result a) -> Value.Value -> Result.Result a
 withNumber s f x = case x of
     Value.Number (Number.Number y z) -> f y z
     _ -> fail $ "expected " <> s <> " but got " <> show x
 
-withString :: String -> (Text.Text -> Result.Result a) -> Type.Value -> Result.Result a
+withString :: String -> (Text.Text -> Result.Result a) -> Value.Value -> Result.Result a
 withString s f x = case x of
     Value.String (String.String y) -> f y
     _ -> fail $ "expected " <> s <> " but got " <> show x
 
-withArray :: String -> (Data.Array.Array Int Type.Value -> Result.Result a) -> Type.Value -> Result.Result a
+withArray :: String -> (Data.Array.Array Int Value.Value -> Result.Result a) -> Value.Value -> Result.Result a
 withArray s f x = case x of
     Value.Array (Array.Array y) -> f y
     _ -> fail $ "expected " <> s <> " but got " <> show x
 
-withObject :: String -> (Data.Array.Array Int (Pair.Pair String.String Type.Value) -> Result.Result a) -> Type.Value -> Result.Result a
+withObject :: String -> (Data.Array.Array Int (Pair.Pair String.String Value.Value) -> Result.Result a) -> Value.Value -> Result.Result a
 withObject s f x = case x of
     Value.Object (Object.Object y) -> f y
     _ -> fail $ "expected " <> s <> " but got " <> show x
 
-viaInteger :: (Integral a, Bits.Bits a) => Type.Value -> Result.Result a
+viaInteger :: (Integral a, Bits.Bits a) => Value.Value -> Result.Result a
 viaInteger value = do
     integer <- fromValue value
     case Bits.toIntegralSized (integer :: Integer) of
diff --git a/source/library/Argo/Class/ToValue.hs b/source/library/Argo/Class/ToValue.hs
--- a/source/library/Argo/Class/ToValue.hs
+++ b/source/library/Argo/Class/ToValue.hs
@@ -2,7 +2,6 @@
 
 module Argo.Class.ToValue where
 
-import qualified Argo.Type as Type
 import qualified Argo.Type.Array as Array
 import qualified Argo.Type.Boolean as Boolean
 import qualified Argo.Type.Null as Null
@@ -22,9 +21,9 @@
 import qualified Numeric
 
 class ToValue a where
-    toValue :: a -> Type.Value
+    toValue :: a -> Value.Value
 
-instance ToValue Type.Value where
+instance ToValue Value.Value where
     toValue = id
 
 instance ToValue Bool where
@@ -85,7 +84,7 @@
     toValue = maybe (Value.Null $ Null.Null ()) toValue
 
 instance ToValue () where
-    toValue = const $ toValue ([] :: [Type.Value])
+    toValue = const $ toValue ([] :: [Value.Value])
 
 instance (ToValue a, ToValue b) => ToValue (a, b) where
     toValue (x, y) = toValue [toValue x, toValue y]
@@ -114,7 +113,16 @@
 realFloatToValue x
     | isNaN x = Value.Null $ Null.Null ()
     | isInfinite x = Value.Null $ Null.Null ()
-    | otherwise = Value.Number . uncurry digitsToNumber $ Numeric.floatToDigits 10 x
+    | otherwise =
+        let isNegative = x < 0
+        in Value.Number
+        . (if isNegative then negateNumber else id)
+        . uncurry digitsToNumber
+        . Numeric.floatToDigits 10
+        $ abs x
+
+negateNumber :: Number.Number -> Number.Number
+negateNumber (Number.Number x y) = Number.Number (-x) y
 
 digitsToNumber :: [Int] -> Int -> Number.Number
 digitsToNumber ds e = uncurry Number.number $ List.foldl'
diff --git a/source/library/Argo/Pattern.hs b/source/library/Argo/Pattern.hs
--- a/source/library/Argo/Pattern.hs
+++ b/source/library/Argo/Pattern.hs
@@ -13,28 +13,28 @@
 import qualified Argo.Type.Value as Value
 import qualified Data.Text as Text
 
-pattern Null :: Type.Value
+pattern Null :: Value.Value
 pattern Null = Value.Null (Null.Null ())
 
-pattern Boolean :: Bool -> Type.Value
+pattern Boolean :: Bool -> Value.Value
 pattern Boolean x = Value.Boolean (Boolean.Boolean x)
 
-pattern Number :: Integer -> Integer -> Type.Value
+pattern Number :: Integer -> Integer -> Value.Value
 pattern Number x y <- Value.Number (Number.Number x y) where
     Number x y = Value.Number $ Number.number x y
 
-pattern String :: Text.Text -> Type.Value
+pattern String :: Text.Text -> Value.Value
 pattern String x = Value.String (String.String x)
 
-pattern Array :: Type.Array -> Type.Value
+pattern Array :: Type.Array -> Value.Value
 pattern Array x = Value.Array (Array.Array x)
 
-pattern Object :: Type.Object -> Type.Value
+pattern Object :: Type.Object -> Value.Value
 pattern Object x = Value.Object (Object.Object x)
 
 {-# COMPLETE Null, Boolean, Number, String, Array, Object #-}
 
-pattern Pair :: Text.Text -> Type.Value -> Type.Pair
+pattern Pair :: Text.Text -> Value.Value -> Pair.Pair String.String Value.Value
 pattern Pair k v = Pair.Pair (String.String k, v)
 
 {-# COMPLETE Pair #-}
diff --git a/source/library/Argo/Type.hs b/source/library/Argo/Type.hs
--- a/source/library/Argo/Type.hs
+++ b/source/library/Argo/Type.hs
@@ -5,10 +5,6 @@
 import qualified Argo.Type.Value as Value
 import qualified Data.Array
 
-type Value = Value.Value
-
-type Array = Data.Array.Array Int Value
-
-type Pair = Pair.Pair String.String Value
+type Array = Data.Array.Array Int Value.Value
 
-type Object = Data.Array.Array Int Pair
+type Object = Data.Array.Array Int (Pair.Pair String.String Value.Value)
diff --git a/source/test-suite/Main.hs b/source/test-suite/Main.hs
--- a/source/test-suite/Main.hs
+++ b/source/test-suite/Main.hs
@@ -1,3 +1,6 @@
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+{-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE QuasiQuotes #-}
 
@@ -418,8 +421,60 @@
     , Tasty.testGroup "property"
         [ Tasty.testProperty "decode . encode" . Tasty.forAll genValue $ \ x -> Tasty.shrinking shrinkValue x $ \ y ->
             (resultToMaybe . Argo.decode . LazyByteString.toStrict . Builder.toLazyByteString $ Argo.encode y) === Just y
-        , Tasty.testProperty "fromValue . toValue" . Tasty.forAll genValue $ \ x -> Tasty.shrinking shrinkValue x $ \ y ->
-            (resultToMaybe . Argo.fromValue $ Argo.toValue y) === Just y
+        , Tasty.testGroup "fromValue . toValue"
+            [ Tasty.testProperty "Value" . Tasty.forAll genValue $ \ x -> Tasty.shrinking shrinkValue x $ \ y ->
+                (resultToMaybe . Argo.fromValue $ Argo.toValue y) === Just y
+            , Tasty.testProperty "Bool" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Bool)
+            , Tasty.testProperty "Char" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Char)
+            , Tasty.testProperty "Int" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Int)
+            , Tasty.testProperty "Int8" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Int.Int8)
+            , Tasty.testProperty "Int16" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Int.Int16)
+            , Tasty.testProperty "Int32" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Int.Int32)
+            , Tasty.testProperty "Int64" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Int.Int64)
+            , Tasty.testProperty "Word" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Word)
+            , Tasty.testProperty "Word8" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Word.Word8)
+            , Tasty.testProperty "Word16" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Word.Word16)
+            , Tasty.testProperty "Word32" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Word.Word32)
+            , Tasty.testProperty "Word64" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Word.Word64)
+            , Tasty.testProperty "Integer" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Integer)
+            , Tasty.testProperty "Float" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Float)
+            , Tasty.testProperty "Double" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Double)
+            , Tasty.testProperty "String" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: String)
+            , Tasty.testProperty "Text" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Text.Text)
+            , Tasty.testProperty "LazyText" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: LazyText.Text)
+            , Tasty.testProperty "Maybe a" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Maybe Bool)
+            , Tasty.testProperty "()" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: ())
+            , Tasty.testProperty "(a, b)" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: (Bool, Int.Int8))
+            , Tasty.testProperty "Array Int a" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Array.Array Int Bool)
+            , Tasty.testProperty "[a]" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: [Bool])
+            , Tasty.testProperty "NonEmpty a" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: NonEmpty Bool)
+            , Tasty.testProperty "Map Text a" $ \ x ->
+                Argo.fromValue (Argo.toValue x) === Argo.Success (x :: Map.Map Text.Text Bool)
+            ]
         ]
     ]
 
@@ -434,14 +489,11 @@
     [ pure Argo.Null
     , Argo.Boolean <$> Tasty.arbitrary
     , Argo.Number <$> Tasty.arbitrary <*> Tasty.arbitrary
-    , Argo.String <$> genText
+    , Argo.String <$> Tasty.arbitrary
     , Argo.Array <$> genArray size (genValueSized newSize)
-    , Argo.Object <$> genArray size (Argo.Pair <$> genText <*> genValueSized newSize)
+    , Argo.Object <$> genArray size (Argo.Pair <$> Tasty.arbitrary <*> genValueSized newSize)
     ]
 
-genText :: Tasty.Gen Text.Text
-genText = Text.pack <$> Tasty.arbitrary
-
 genArray :: Int -> Tasty.Gen a -> Tasty.Gen (Array.Array Int a)
 genArray n = fmap (Array.listArray (0, n - 1)) . Tasty.vectorOf n
 
@@ -452,12 +504,9 @@
     Argo.Null -> []
     Argo.Boolean y -> Argo.Boolean <$> Tasty.shrink y
     Argo.Number y z -> uncurry Argo.Number <$> Tasty.shrink (y, z)
-    Argo.String y -> Argo.String <$> shrinkText y
+    Argo.String y -> Argo.String <$> Tasty.shrink y
     Argo.Array y -> Argo.Array <$> shrinkArray shrinkValue y
-    Argo.Object y -> Argo.Object <$> shrinkArray (\ (Argo.Pair k v) -> Argo.Pair <$> shrinkText k <*> shrinkValue v) y
-
-shrinkText :: Shrink Text.Text
-shrinkText = Tasty.shrinkMap Text.pack Text.unpack
+    Argo.Object y -> Argo.Object <$> shrinkArray (\ (Argo.Pair k v) -> Argo.Pair <$> Tasty.shrink k <*> shrinkValue v) y
 
 shrinkArray :: Shrink a -> Shrink (Array.Array Int a)
 shrinkArray = Tasty.shrinkMapBy array Array.elems . Tasty.shrinkList
@@ -466,3 +515,19 @@
 resultToMaybe r = case r of
     Argo.Failure _ -> Nothing
     Argo.Success x -> Just x
+
+instance Tasty.Arbitrary Text.Text where
+    arbitrary = Text.pack <$> Tasty.arbitrary
+    shrink = Tasty.shrinkMap Text.pack Text.unpack
+
+instance Tasty.Arbitrary LazyText.Text where
+    arbitrary = LazyText.pack <$> Tasty.arbitrary
+    shrink = Tasty.shrinkMap LazyText.pack LazyText.unpack
+
+instance Tasty.Arbitrary a => Tasty.Arbitrary (NonEmpty a) where
+    arbitrary = (:|) <$> Tasty.arbitrary <*> Tasty.arbitrary
+    shrink (x :| xs) = uncurry (:|) <$> Tasty.shrink (x, xs)
+
+instance Tasty.Arbitrary a => Tasty.Arbitrary (Array.Array Int a) where
+    arbitrary = array <$> Tasty.arbitrary
+    shrink = Tasty.shrinkMap array Array.elems
