diff --git a/pgp-wordlist.cabal b/pgp-wordlist.cabal
--- a/pgp-wordlist.cabal
+++ b/pgp-wordlist.cabal
@@ -1,8 +1,5 @@
--- Initial pgp-wordlist.cabal generated by cabal init.  For further
--- documentation, see http://haskell.org/cabal/users-guide/
-
 name:                pgp-wordlist
-version:             0.1.0.1
+version:             0.1.0.2
 synopsis:            Translate between binary data and a human-readable
                      collection of words.
 description:         Translate between binary data and a human-readable
@@ -29,9 +26,7 @@
 build-type:          Simple
 cabal-version:       >=1.10
 extra-source-files:  README.md
-tested-with:         GHC == 7.6.3
-                   , GHC == 7.8.4
-                   , GHC == 7.10.1
+tested-with:         GHC == 7.10.3
 
 
 
@@ -67,8 +62,21 @@
     build-depends:    pgp-wordlist
                     , base
                     , bytestring
+                    , deepseq
                     , HUnit
                     , tasty >= 0.10
                     , tasty-hunit >= 0.9
                     , tasty-quickcheck
                     , text
+
+
+
+test-suite doctest
+    type: exitcode-stdio-1.0
+    hs-source-dirs: test
+    main-is: Doctest.hs
+    build-depends:
+                      base
+                    , doctest >= 0.10
+    ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
+    default-language: Haskell2010
diff --git a/src/Data/Text/PgpWordlist.hs b/src/Data/Text/PgpWordlist.hs
--- a/src/Data/Text/PgpWordlist.hs
+++ b/src/Data/Text/PgpWordlist.hs
@@ -7,5 +7,5 @@
 
 
 
-import           Data.Text.PgpWordlist.Internal.Convert
-import           Data.Text.PgpWordlist.Internal.Types
+import Data.Text.PgpWordlist.Internal.Convert
+import Data.Text.PgpWordlist.Internal.Types
diff --git a/src/Data/Text/PgpWordlist/Internal/Convert.hs b/src/Data/Text/PgpWordlist/Internal/Convert.hs
--- a/src/Data/Text/PgpWordlist/Internal/Convert.hs
+++ b/src/Data/Text/PgpWordlist/Internal/Convert.hs
@@ -6,19 +6,22 @@
 
 
 
-import qualified Data.Text.PgpWordlist.Internal.AltList as Alt
+import qualified Data.Text.PgpWordlist.Internal.AltList    as Alt
 import           Data.Text.PgpWordlist.Internal.Types
-import           Data.Text.PgpWordlist.Internal.Words
 import           Data.Text.PgpWordlist.Internal.Word8Bimap
+import           Data.Text.PgpWordlist.Internal.Words
 
-import qualified Data.ByteString.Lazy                   as BSL
-import           Data.Text                              (Text)
-import qualified Data.Text                              as T
+import qualified Data.ByteString.Lazy as BSL
+import           Data.Text            (Text)
+import qualified Data.Text            as T
 import           Data.Word
 
 
 
 -- | Inverse of 'fromText', modulo whitespace count.
+--
+-- >>> toText (BSL.pack [104, 101, 108, 108, 111])
+-- "frighten glossary glucose handiwork gremlin"
 toText :: BSL.ByteString -> Text
 toText = T.intercalate " "
        . Alt.toList
@@ -30,6 +33,20 @@
 
 -- | Convert a text of whitespace-separated words to their binary
 --   representation. The whitespace splitting behaviour is given by 'T.words'.
+--
+-- >>> fromText (T.pack "frighten glossary glucose handiwork gremlin")
+-- Right "hello"
+--
+-- Invalid words are recognized:
+--
+-- >>> fromText (T.pack "frighten dragon glucose handiwork gremlin")
+-- Left (BadWord "dragon")
+--
+-- Typical mistakes include accidentally swapping numbers, which leads to a
+-- parity error:
+--
+-- >>> fromText (T.pack "frighten glucose glossary handiwork gremlin")
+-- Left (BadParity "glucose" 108)
 fromText :: Text -> Either TranslationError BSL.ByteString
 fromText = fmap (BSL.pack . Alt.toList)
          . Alt.bitraverse fromEvenWord fromOddWord
@@ -50,19 +67,22 @@
 
 -- | Simple conversion, taking into account invalid words.
 fromEvenWord :: Text -> Either TranslationError Word8
-fromEvenWord word = case lookupR evenMap (EvenWord word) of
-    Just i  -> Right i
-    Nothing -> Left (case lookupR oddMap (OddWord word) of
-        Just j  -> BadParity word j
-        Nothing -> BadWord word)
+fromEvenWord word = case lookupEvenOdd word of
+    (Just byte, _x       ) -> Right byte
+    (Nothing  , Just byte) -> Left (BadParity word byte)
+    (Nothing  , Nothing  ) -> Left (BadWord word)
 
 -- | Simple conversion, taking into account invalid words.
 fromOddWord :: Text -> Either TranslationError Word8
-fromOddWord word = case lookupR oddMap (OddWord word) of
-    Just i  -> Right i
-    Nothing -> Left (case lookupR evenMap (EvenWord word) of
-        Just j  -> BadParity word j
-        Nothing -> BadWord word)
+fromOddWord word = case lookupEvenOdd word of
+    (_x       , Just byte) -> Right byte
+    (Just byte, Nothing  ) -> Left (BadParity word byte)
+    (Nothing  , Nothing  ) -> Left (BadWord word)
+
+-- | Look up a word in both databases.
+lookupEvenOdd :: Text -> (Maybe Word8, Maybe Word8)
+lookupEvenOdd word = ( lookupR evenMap (EvenWord word)
+                     , lookupR oddMap  (OddWord word) )
 
 
 
diff --git a/src/Data/Text/PgpWordlist/Internal/Types.hs b/src/Data/Text/PgpWordlist/Internal/Types.hs
--- a/src/Data/Text/PgpWordlist/Internal/Types.hs
+++ b/src/Data/Text/PgpWordlist/Internal/Types.hs
@@ -2,9 +2,9 @@
 
 
 
-import           Data.Text                              (Text)
-import           Data.Text.PgpWordlist.Internal.AltList
-import           Data.Word
+import Data.Text                              (Text)
+import Data.Text.PgpWordlist.Internal.AltList
+import Data.Word
 
 
 
diff --git a/src/Data/Text/PgpWordlist/Internal/Word8Bimap.hs b/src/Data/Text/PgpWordlist/Internal/Word8Bimap.hs
--- a/src/Data/Text/PgpWordlist/Internal/Word8Bimap.hs
+++ b/src/Data/Text/PgpWordlist/Internal/Word8Bimap.hs
@@ -15,8 +15,8 @@
 import           Data.Vector (Vector, (!))
 import qualified Data.Vector as V
 
-import           Data.Tuple
-import           Data.Word
+import Data.Tuple
+import Data.Word
 
 
 
diff --git a/src/Data/Text/PgpWordlist/Internal/Words.hs b/src/Data/Text/PgpWordlist/Internal/Words.hs
--- a/src/Data/Text/PgpWordlist/Internal/Words.hs
+++ b/src/Data/Text/PgpWordlist/Internal/Words.hs
@@ -4,269 +4,269 @@
 
 
 
-import           Data.Text.PgpWordlist.Internal.Types
-import           Data.Word
+import Data.Text.PgpWordlist.Internal.Types
 
+import Data.Word
 
 
+
 -- | Database of PGP words
 wordList :: [(Word8, EvenWord, OddWord)]
-wordList = map (\(i,e,o) -> (i, EvenWord e, OddWord o)) table
-  where
-    table = [ (0x00, "aardvark" , "adroitness" )
-            , (0x01, "absurd"   , "adviser"    )
-            , (0x02, "accrue"   , "aftermath"  )
-            , (0x03, "acme"     , "aggregate"  )
-            , (0x04, "adrift"   , "alkali"     )
-            , (0x05, "adult"    , "almighty"   )
-            , (0x06, "afflict"  , "amulet"     )
-            , (0x07, "ahead"    , "amusement"  )
-            , (0x08, "aimless"  , "antenna"    )
-            , (0x09, "algol"    , "applicant"  )
-            , (0x0a, "allow"    , "apollo"     )
-            , (0x0b, "alone"    , "armistice"  )
-            , (0x0c, "ammo"     , "article"    )
-            , (0x0d, "ancient"  , "asteroid"   )
-            , (0x0e, "apple"    , "atlantic"   )
-            , (0x0f, "artist"   , "atmosphere" )
-            , (0x10, "assume"   , "autopsy"    )
-            , (0x11, "athens"   , "babylon"    )
-            , (0x12, "atlas"    , "backwater"  )
-            , (0x13, "aztec"    , "barbecue"   )
-            , (0x14, "baboon"   , "belowground")
-            , (0x15, "backfield", "bifocals"   )
-            , (0x16, "backward" , "bodyguard"  )
-            , (0x17, "banjo"    , "bookseller" )
-            , (0x18, "beaming"  , "borderline" )
-            , (0x19, "bedlamp"  , "bottomless" )
-            , (0x1a, "beehive"  , "bradbury"   )
-            , (0x1b, "beeswax"  , "bravado"    )
-            , (0x1c, "befriend" , "brazilian"  )
-            , (0x1d, "belfast"  , "breakaway"  )
-            , (0x1e, "berserk"  , "burlington" )
-            , (0x1f, "billiard" , "businessman")
-            , (0x20, "bison"    , "butterfat"  )
-            , (0x21, "blackjack", "camelot"    )
-            , (0x22, "blockade" , "candidate"  )
-            , (0x23, "blowtorch", "cannonball" )
-            , (0x24, "bluebird" , "capricorn"  )
-            , (0x25, "bombast"  , "caravan"    )
-            , (0x26, "bookshelf", "caretaker"  )
-            , (0x27, "brackish" , "celebrate"  )
-            , (0x28, "breadline", "cellulose"  )
-            , (0x29, "breakup"  , "certify"    )
-            , (0x2a, "brickyard", "chambermaid")
-            , (0x2b, "briefcase", "cherokee"   )
-            , (0x2c, "burbank"  , "chicago"    )
-            , (0x2d, "button"   , "clergyman"  )
-            , (0x2e, "buzzard"  , "coherence"  )
-            , (0x2f, "cement"   , "combustion" )
-            , (0x30, "chairlift", "commando"   )
-            , (0x31, "chatter"  , "company"    )
-            , (0x32, "checkup"  , "component"  )
-            , (0x33, "chisel"   , "concurrent" )
-            , (0x34, "choking"  , "confidence" )
-            , (0x35, "chopper"  , "conformist" )
-            , (0x36, "christmas", "congregate" )
-            , (0x37, "clamshell", "consensus"  )
-            , (0x38, "classic"  , "consulting" )
-            , (0x39, "classroom", "corporate"  )
-            , (0x3a, "cleanup"  , "corrosion"  )
-            , (0x3b, "clockwork", "councilman" )
-            , (0x3c, "cobra"    , "crossover"  )
-            , (0x3d, "commence" , "crucifix"   )
-            , (0x3e, "concert"  , "cumbersome" )
-            , (0x3f, "cowbell"  , "customer"   )
-            , (0x40, "crackdown", "dakota"     )
-            , (0x41, "cranky"   , "decadence"  )
-            , (0x42, "crowfoot" , "december"   )
-            , (0x43, "crucial"  , "decimal"    )
-            , (0x44, "crumpled" , "designing"  )
-            , (0x45, "crusade"  , "detector"   )
-            , (0x46, "cubic"    , "detergent"  )
-            , (0x47, "dashboard", "determine"  )
-            , (0x48, "deadbolt" , "dictator"   )
-            , (0x49, "deckhand" , "dinosaur"   )
-            , (0x4a, "dogsled"  , "direction"  )
-            , (0x4b, "dragnet"  , "disable"    )
-            , (0x4c, "drainage" , "disbelief"  )
-            , (0x4d, "dreadful" , "disruptive" )
-            , (0x4e, "drifter"  , "distortion" )
-            , (0x4f, "dropper"  , "document"   )
-            , (0x50, "drumbeat" , "embezzle"   )
-            , (0x51, "drunken"  , "enchanting" )
-            , (0x52, "dupont"   , "enrollment" )
-            , (0x53, "dwelling" , "enterprise" )
-            , (0x54, "eating"   , "equation"   )
-            , (0x55, "edict"    , "equipment"  )
-            , (0x56, "egghead"  , "escapade"   )
-            , (0x57, "eightball", "eskimo"     )
-            , (0x58, "endorse"  , "everyday"   )
-            , (0x59, "endow"    , "examine"    )
-            , (0x5a, "enlist"   , "existence"  )
-            , (0x5b, "erase"    , "exodus"     )
-            , (0x5c, "escape"   , "fascinate"  )
-            , (0x5d, "exceed"   , "filament"   )
-            , (0x5e, "eyeglass" , "finicky"    )
-            , (0x5f, "eyetooth" , "forever"    )
-            , (0x60, "facial"   , "fortitude"  )
-            , (0x61, "fallout"  , "frequency"  )
-            , (0x62, "flagpole" , "gadgetry"   )
-            , (0x63, "flatfoot" , "galveston"  )
-            , (0x64, "flytrap"  , "getaway"    )
-            , (0x65, "fracture" , "glossary"   )
-            , (0x66, "framework", "gossamer"   )
-            , (0x67, "freedom"  , "graduate"   )
-            , (0x68, "frighten" , "gravity"    )
-            , (0x69, "gazelle"  , "guitarist"  )
-            , (0x6a, "geiger"   , "hamburger"  )
-            , (0x6b, "glitter"  , "hamilton"   )
-            , (0x6c, "glucose"  , "handiwork"  )
-            , (0x6d, "goggles"  , "hazardous"  )
-            , (0x6e, "goldfish" , "headwaters" )
-            , (0x6f, "gremlin"  , "hemisphere" )
-            , (0x70, "guidance" , "hesitate"   )
-            , (0x71, "hamlet"   , "hideaway"   )
-            , (0x72, "highchair", "holiness"   )
-            , (0x73, "hockey"   , "hurricane"  )
-            , (0x74, "indoors"  , "hydraulic"  )
-            , (0x75, "indulge"  , "impartial"  )
-            , (0x76, "inverse"  , "impetus"    )
-            , (0x77, "involve"  , "inception"  )
-            , (0x78, "island"   , "indigo"     )
-            , (0x79, "jawbone"  , "inertia"    )
-            , (0x7a, "keyboard" , "infancy"    )
-            , (0x7b, "kickoff"  , "inferno"    )
-            , (0x7c, "kiwi"     , "informant"  )
-            , (0x7d, "klaxon"   , "insincere"  )
-            , (0x7e, "locale"   , "insurgent"  )
-            , (0x7f, "lockup"   , "integrate"  )
-            , (0x80, "merit"    , "intention"  )
-            , (0x81, "minnow"   , "inventive"  )
-            , (0x82, "miser"    , "istanbul"   )
-            , (0x83, "mohawk"   , "jamaica"    )
-            , (0x84, "mural"    , "jupiter"    )
-            , (0x85, "music"    , "leprosy"    )
-            , (0x86, "necklace" , "letterhead" )
-            , (0x87, "neptune"  , "liberty"    )
-            , (0x88, "newborn"  , "maritime"   )
-            , (0x89, "nightbird", "matchmaker" )
-            , (0x8a, "oakland"  , "maverick"   )
-            , (0x8b, "obtuse"   , "medusa"     )
-            , (0x8c, "offload"  , "megaton"    )
-            , (0x8d, "optic"    , "microscope" )
-            , (0x8e, "orca"     , "microwave"  )
-            , (0x8f, "payday"   , "midsummer"  )
-            , (0x90, "peachy"   , "millionaire")
-            , (0x91, "pheasant" , "miracle"    )
-            , (0x92, "physique" , "misnomer"   )
-            , (0x93, "playhouse", "molasses"   )
-            , (0x94, "pluto"    , "molecule"   )
-            , (0x95, "preclude" , "montana"    )
-            , (0x96, "prefer"   , "monument"   )
-            , (0x97, "preshrunk", "mosquito"   )
-            , (0x98, "printer"  , "narrative"  )
-            , (0x99, "prowler"  , "nebula"     )
-            , (0x9a, "pupil"    , "newsletter" )
-            , (0x9b, "puppy"    , "norwegian"  )
-            , (0x9c, "python"   , "october"    )
-            , (0x9d, "quadrant" , "ohio"       )
-            , (0x9e, "quiver"   , "onlooker"   )
-            , (0x9f, "quota"    , "opulent"    )
-            , (0xa0, "ragtime"  , "orlando"    )
-            , (0xa1, "ratchet"  , "outfielder" )
-            , (0xa2, "rebirth"  , "pacific"    )
-            , (0xa3, "reform"   , "pandemic"   )
-            , (0xa4, "regain"   , "pandora"    )
-            , (0xa5, "reindeer" , "paperweight")
-            , (0xa6, "rematch"  , "paragon"    )
-            , (0xa7, "repay"    , "paragraph"  )
-            , (0xa8, "retouch"  , "paramount"  )
-            , (0xa9, "revenge"  , "passenger"  )
-            , (0xaa, "reward"   , "pedigree"   )
-            , (0xab, "rhythm"   , "pegasus"    )
-            , (0xac, "ribcage"  , "penetrate"  )
-            , (0xad, "ringbolt" , "perceptive" )
-            , (0xae, "robust"   , "performance")
-            , (0xaf, "rocker"   , "pharmacy"   )
-            , (0xb0, "ruffled"  , "phonetic"   )
-            , (0xb1, "sailboat" , "photograph" )
-            , (0xb2, "sawdust"  , "pioneer"    )
-            , (0xb3, "scallion" , "pocketful"  )
-            , (0xb4, "scenic"   , "politeness" )
-            , (0xb5, "scorecard", "positive"   )
-            , (0xb6, "scotland" , "potato"     )
-            , (0xb7, "seabird"  , "processor"  )
-            , (0xb8, "select"   , "provincial" )
-            , (0xb9, "sentence" , "proximate"  )
-            , (0xba, "shadow"   , "puberty"    )
-            , (0xbb, "shamrock" , "publisher"  )
-            , (0xbc, "showgirl" , "pyramid"    )
-            , (0xbd, "skullcap" , "quantity"   )
-            , (0xbe, "skydive"  , "racketeer"  )
-            , (0xbf, "slingshot", "rebellion"  )
-            , (0xc0, "slowdown" , "recipe"     )
-            , (0xc1, "snapline" , "recover"    )
-            , (0xc2, "snapshot" , "repellent"  )
-            , (0xc3, "snowcap"  , "replica"    )
-            , (0xc4, "snowslide", "reproduce"  )
-            , (0xc5, "solo"     , "resistor"   )
-            , (0xc6, "southward", "responsive" )
-            , (0xc7, "soybean"  , "retraction" )
-            , (0xc8, "spaniel"  , "retrieval"  )
-            , (0xc9, "spearhead", "retrospect" )
-            , (0xca, "spellbind", "revenue"    )
-            , (0xcb, "spheroid" , "revival"    )
-            , (0xcc, "spigot"   , "revolver"   )
-            , (0xcd, "spindle"  , "sandalwood" )
-            , (0xce, "spyglass" , "sardonic"   )
-            , (0xcf, "stagehand", "saturday"   )
-            , (0xd0, "stagnate" , "savagery"   )
-            , (0xd1, "stairway" , "scavenger"  )
-            , (0xd2, "standard" , "sensation"  )
-            , (0xd3, "stapler"  , "sociable"   )
-            , (0xd4, "steamship", "souvenir"   )
-            , (0xd5, "sterling" , "specialist" )
-            , (0xd6, "stockman" , "speculate"  )
-            , (0xd7, "stopwatch", "stethoscope")
-            , (0xd8, "stormy"   , "stupendous" )
-            , (0xd9, "sugar"    , "supportive" )
-            , (0xda, "surmount" , "surrender"  )
-            , (0xdb, "suspense" , "suspicious" )
-            , (0xdc, "sweatband", "sympathy"   )
-            , (0xdd, "swelter"  , "tambourine" )
-            , (0xde, "tactics"  , "telephone"  )
-            , (0xdf, "talon"    , "therapist"  )
-            , (0xe0, "tapeworm" , "tobacco"    )
-            , (0xe1, "tempest"  , "tolerance"  )
-            , (0xe2, "tiger"    , "tomorrow"   )
-            , (0xe3, "tissue"   , "torpedo"    )
-            , (0xe4, "tonic"    , "tradition"  )
-            , (0xe5, "topmost"  , "travesty"   )
-            , (0xe6, "tracker"  , "trombonist" )
-            , (0xe7, "transit"  , "truncated"  )
-            , (0xe8, "trauma"   , "typewriter" )
-            , (0xe9, "treadmill", "ultimate"   )
-            , (0xea, "trojan"   , "undaunted"  )
-            , (0xeb, "trouble"  , "underfoot"  )
-            , (0xec, "tumor"    , "unicorn"    )
-            , (0xed, "tunnel"   , "unify"      )
-            , (0xee, "tycoon"   , "universe"   )
-            , (0xef, "uncut"    , "unravel"    )
-            , (0xf0, "unearth"  , "upcoming"   )
-            , (0xf1, "unwind"   , "vacancy"    )
-            , (0xf2, "uproot"   , "vagabond"   )
-            , (0xf3, "upset"    , "vertigo"    )
-            , (0xf4, "upshot"   , "virginia"   )
-            , (0xf5, "vapor"    , "visitor"    )
-            , (0xf6, "village"  , "vocalist"   )
-            , (0xf7, "virus"    , "voyager"    )
-            , (0xf8, "vulcan"   , "warranty"   )
-            , (0xf9, "waffle"   , "waterloo"   )
-            , (0xfa, "wallet"   , "whimsical"  )
-            , (0xfb, "watchword", "wichita"    )
-            , (0xfc, "wayside"  , "wilmington" )
-            , (0xfd, "willow"   , "wyoming"    )
-            , (0xfe, "woodlark" , "yesteryear" )
-            , (0xff, "zulu"     , "yucatan"    )
-            ]
+wordList = map (\(i,e,o) -> (i, EvenWord e, OddWord o))
+    [ (0x00, "aardvark" , "adroitness" )
+    , (0x01, "absurd"   , "adviser"    )
+    , (0x02, "accrue"   , "aftermath"  )
+    , (0x03, "acme"     , "aggregate"  )
+    , (0x04, "adrift"   , "alkali"     )
+    , (0x05, "adult"    , "almighty"   )
+    , (0x06, "afflict"  , "amulet"     )
+    , (0x07, "ahead"    , "amusement"  )
+    , (0x08, "aimless"  , "antenna"    )
+    , (0x09, "algol"    , "applicant"  )
+    , (0x0a, "allow"    , "apollo"     )
+    , (0x0b, "alone"    , "armistice"  )
+    , (0x0c, "ammo"     , "article"    )
+    , (0x0d, "ancient"  , "asteroid"   )
+    , (0x0e, "apple"    , "atlantic"   )
+    , (0x0f, "artist"   , "atmosphere" )
+    , (0x10, "assume"   , "autopsy"    )
+    , (0x11, "athens"   , "babylon"    )
+    , (0x12, "atlas"    , "backwater"  )
+    , (0x13, "aztec"    , "barbecue"   )
+    , (0x14, "baboon"   , "belowground")
+    , (0x15, "backfield", "bifocals"   )
+    , (0x16, "backward" , "bodyguard"  )
+    , (0x17, "banjo"    , "bookseller" )
+    , (0x18, "beaming"  , "borderline" )
+    , (0x19, "bedlamp"  , "bottomless" )
+    , (0x1a, "beehive"  , "bradbury"   )
+    , (0x1b, "beeswax"  , "bravado"    )
+    , (0x1c, "befriend" , "brazilian"  )
+    , (0x1d, "belfast"  , "breakaway"  )
+    , (0x1e, "berserk"  , "burlington" )
+    , (0x1f, "billiard" , "businessman")
+    , (0x20, "bison"    , "butterfat"  )
+    , (0x21, "blackjack", "camelot"    )
+    , (0x22, "blockade" , "candidate"  )
+    , (0x23, "blowtorch", "cannonball" )
+    , (0x24, "bluebird" , "capricorn"  )
+    , (0x25, "bombast"  , "caravan"    )
+    , (0x26, "bookshelf", "caretaker"  )
+    , (0x27, "brackish" , "celebrate"  )
+    , (0x28, "breadline", "cellulose"  )
+    , (0x29, "breakup"  , "certify"    )
+    , (0x2a, "brickyard", "chambermaid")
+    , (0x2b, "briefcase", "cherokee"   )
+    , (0x2c, "burbank"  , "chicago"    )
+    , (0x2d, "button"   , "clergyman"  )
+    , (0x2e, "buzzard"  , "coherence"  )
+    , (0x2f, "cement"   , "combustion" )
+    , (0x30, "chairlift", "commando"   )
+    , (0x31, "chatter"  , "company"    )
+    , (0x32, "checkup"  , "component"  )
+    , (0x33, "chisel"   , "concurrent" )
+    , (0x34, "choking"  , "confidence" )
+    , (0x35, "chopper"  , "conformist" )
+    , (0x36, "christmas", "congregate" )
+    , (0x37, "clamshell", "consensus"  )
+    , (0x38, "classic"  , "consulting" )
+    , (0x39, "classroom", "corporate"  )
+    , (0x3a, "cleanup"  , "corrosion"  )
+    , (0x3b, "clockwork", "councilman" )
+    , (0x3c, "cobra"    , "crossover"  )
+    , (0x3d, "commence" , "crucifix"   )
+    , (0x3e, "concert"  , "cumbersome" )
+    , (0x3f, "cowbell"  , "customer"   )
+    , (0x40, "crackdown", "dakota"     )
+    , (0x41, "cranky"   , "decadence"  )
+    , (0x42, "crowfoot" , "december"   )
+    , (0x43, "crucial"  , "decimal"    )
+    , (0x44, "crumpled" , "designing"  )
+    , (0x45, "crusade"  , "detector"   )
+    , (0x46, "cubic"    , "detergent"  )
+    , (0x47, "dashboard", "determine"  )
+    , (0x48, "deadbolt" , "dictator"   )
+    , (0x49, "deckhand" , "dinosaur"   )
+    , (0x4a, "dogsled"  , "direction"  )
+    , (0x4b, "dragnet"  , "disable"    )
+    , (0x4c, "drainage" , "disbelief"  )
+    , (0x4d, "dreadful" , "disruptive" )
+    , (0x4e, "drifter"  , "distortion" )
+    , (0x4f, "dropper"  , "document"   )
+    , (0x50, "drumbeat" , "embezzle"   )
+    , (0x51, "drunken"  , "enchanting" )
+    , (0x52, "dupont"   , "enrollment" )
+    , (0x53, "dwelling" , "enterprise" )
+    , (0x54, "eating"   , "equation"   )
+    , (0x55, "edict"    , "equipment"  )
+    , (0x56, "egghead"  , "escapade"   )
+    , (0x57, "eightball", "eskimo"     )
+    , (0x58, "endorse"  , "everyday"   )
+    , (0x59, "endow"    , "examine"    )
+    , (0x5a, "enlist"   , "existence"  )
+    , (0x5b, "erase"    , "exodus"     )
+    , (0x5c, "escape"   , "fascinate"  )
+    , (0x5d, "exceed"   , "filament"   )
+    , (0x5e, "eyeglass" , "finicky"    )
+    , (0x5f, "eyetooth" , "forever"    )
+    , (0x60, "facial"   , "fortitude"  )
+    , (0x61, "fallout"  , "frequency"  )
+    , (0x62, "flagpole" , "gadgetry"   )
+    , (0x63, "flatfoot" , "galveston"  )
+    , (0x64, "flytrap"  , "getaway"    )
+    , (0x65, "fracture" , "glossary"   )
+    , (0x66, "framework", "gossamer"   )
+    , (0x67, "freedom"  , "graduate"   )
+    , (0x68, "frighten" , "gravity"    )
+    , (0x69, "gazelle"  , "guitarist"  )
+    , (0x6a, "geiger"   , "hamburger"  )
+    , (0x6b, "glitter"  , "hamilton"   )
+    , (0x6c, "glucose"  , "handiwork"  )
+    , (0x6d, "goggles"  , "hazardous"  )
+    , (0x6e, "goldfish" , "headwaters" )
+    , (0x6f, "gremlin"  , "hemisphere" )
+    , (0x70, "guidance" , "hesitate"   )
+    , (0x71, "hamlet"   , "hideaway"   )
+    , (0x72, "highchair", "holiness"   )
+    , (0x73, "hockey"   , "hurricane"  )
+    , (0x74, "indoors"  , "hydraulic"  )
+    , (0x75, "indulge"  , "impartial"  )
+    , (0x76, "inverse"  , "impetus"    )
+    , (0x77, "involve"  , "inception"  )
+    , (0x78, "island"   , "indigo"     )
+    , (0x79, "jawbone"  , "inertia"    )
+    , (0x7a, "keyboard" , "infancy"    )
+    , (0x7b, "kickoff"  , "inferno"    )
+    , (0x7c, "kiwi"     , "informant"  )
+    , (0x7d, "klaxon"   , "insincere"  )
+    , (0x7e, "locale"   , "insurgent"  )
+    , (0x7f, "lockup"   , "integrate"  )
+    , (0x80, "merit"    , "intention"  )
+    , (0x81, "minnow"   , "inventive"  )
+    , (0x82, "miser"    , "istanbul"   )
+    , (0x83, "mohawk"   , "jamaica"    )
+    , (0x84, "mural"    , "jupiter"    )
+    , (0x85, "music"    , "leprosy"    )
+    , (0x86, "necklace" , "letterhead" )
+    , (0x87, "neptune"  , "liberty"    )
+    , (0x88, "newborn"  , "maritime"   )
+    , (0x89, "nightbird", "matchmaker" )
+    , (0x8a, "oakland"  , "maverick"   )
+    , (0x8b, "obtuse"   , "medusa"     )
+    , (0x8c, "offload"  , "megaton"    )
+    , (0x8d, "optic"    , "microscope" )
+    , (0x8e, "orca"     , "microwave"  )
+    , (0x8f, "payday"   , "midsummer"  )
+    , (0x90, "peachy"   , "millionaire")
+    , (0x91, "pheasant" , "miracle"    )
+    , (0x92, "physique" , "misnomer"   )
+    , (0x93, "playhouse", "molasses"   )
+    , (0x94, "pluto"    , "molecule"   )
+    , (0x95, "preclude" , "montana"    )
+    , (0x96, "prefer"   , "monument"   )
+    , (0x97, "preshrunk", "mosquito"   )
+    , (0x98, "printer"  , "narrative"  )
+    , (0x99, "prowler"  , "nebula"     )
+    , (0x9a, "pupil"    , "newsletter" )
+    , (0x9b, "puppy"    , "norwegian"  )
+    , (0x9c, "python"   , "october"    )
+    , (0x9d, "quadrant" , "ohio"       )
+    , (0x9e, "quiver"   , "onlooker"   )
+    , (0x9f, "quota"    , "opulent"    )
+    , (0xa0, "ragtime"  , "orlando"    )
+    , (0xa1, "ratchet"  , "outfielder" )
+    , (0xa2, "rebirth"  , "pacific"    )
+    , (0xa3, "reform"   , "pandemic"   )
+    , (0xa4, "regain"   , "pandora"    )
+    , (0xa5, "reindeer" , "paperweight")
+    , (0xa6, "rematch"  , "paragon"    )
+    , (0xa7, "repay"    , "paragraph"  )
+    , (0xa8, "retouch"  , "paramount"  )
+    , (0xa9, "revenge"  , "passenger"  )
+    , (0xaa, "reward"   , "pedigree"   )
+    , (0xab, "rhythm"   , "pegasus"    )
+    , (0xac, "ribcage"  , "penetrate"  )
+    , (0xad, "ringbolt" , "perceptive" )
+    , (0xae, "robust"   , "performance")
+    , (0xaf, "rocker"   , "pharmacy"   )
+    , (0xb0, "ruffled"  , "phonetic"   )
+    , (0xb1, "sailboat" , "photograph" )
+    , (0xb2, "sawdust"  , "pioneer"    )
+    , (0xb3, "scallion" , "pocketful"  )
+    , (0xb4, "scenic"   , "politeness" )
+    , (0xb5, "scorecard", "positive"   )
+    , (0xb6, "scotland" , "potato"     )
+    , (0xb7, "seabird"  , "processor"  )
+    , (0xb8, "select"   , "provincial" )
+    , (0xb9, "sentence" , "proximate"  )
+    , (0xba, "shadow"   , "puberty"    )
+    , (0xbb, "shamrock" , "publisher"  )
+    , (0xbc, "showgirl" , "pyramid"    )
+    , (0xbd, "skullcap" , "quantity"   )
+    , (0xbe, "skydive"  , "racketeer"  )
+    , (0xbf, "slingshot", "rebellion"  )
+    , (0xc0, "slowdown" , "recipe"     )
+    , (0xc1, "snapline" , "recover"    )
+    , (0xc2, "snapshot" , "repellent"  )
+    , (0xc3, "snowcap"  , "replica"    )
+    , (0xc4, "snowslide", "reproduce"  )
+    , (0xc5, "solo"     , "resistor"   )
+    , (0xc6, "southward", "responsive" )
+    , (0xc7, "soybean"  , "retraction" )
+    , (0xc8, "spaniel"  , "retrieval"  )
+    , (0xc9, "spearhead", "retrospect" )
+    , (0xca, "spellbind", "revenue"    )
+    , (0xcb, "spheroid" , "revival"    )
+    , (0xcc, "spigot"   , "revolver"   )
+    , (0xcd, "spindle"  , "sandalwood" )
+    , (0xce, "spyglass" , "sardonic"   )
+    , (0xcf, "stagehand", "saturday"   )
+    , (0xd0, "stagnate" , "savagery"   )
+    , (0xd1, "stairway" , "scavenger"  )
+    , (0xd2, "standard" , "sensation"  )
+    , (0xd3, "stapler"  , "sociable"   )
+    , (0xd4, "steamship", "souvenir"   )
+    , (0xd5, "sterling" , "specialist" )
+    , (0xd6, "stockman" , "speculate"  )
+    , (0xd7, "stopwatch", "stethoscope")
+    , (0xd8, "stormy"   , "stupendous" )
+    , (0xd9, "sugar"    , "supportive" )
+    , (0xda, "surmount" , "surrender"  )
+    , (0xdb, "suspense" , "suspicious" )
+    , (0xdc, "sweatband", "sympathy"   )
+    , (0xdd, "swelter"  , "tambourine" )
+    , (0xde, "tactics"  , "telephone"  )
+    , (0xdf, "talon"    , "therapist"  )
+    , (0xe0, "tapeworm" , "tobacco"    )
+    , (0xe1, "tempest"  , "tolerance"  )
+    , (0xe2, "tiger"    , "tomorrow"   )
+    , (0xe3, "tissue"   , "torpedo"    )
+    , (0xe4, "tonic"    , "tradition"  )
+    , (0xe5, "topmost"  , "travesty"   )
+    , (0xe6, "tracker"  , "trombonist" )
+    , (0xe7, "transit"  , "truncated"  )
+    , (0xe8, "trauma"   , "typewriter" )
+    , (0xe9, "treadmill", "ultimate"   )
+    , (0xea, "trojan"   , "undaunted"  )
+    , (0xeb, "trouble"  , "underfoot"  )
+    , (0xec, "tumor"    , "unicorn"    )
+    , (0xed, "tunnel"   , "unify"      )
+    , (0xee, "tycoon"   , "universe"   )
+    , (0xef, "uncut"    , "unravel"    )
+    , (0xf0, "unearth"  , "upcoming"   )
+    , (0xf1, "unwind"   , "vacancy"    )
+    , (0xf2, "uproot"   , "vagabond"   )
+    , (0xf3, "upset"    , "vertigo"    )
+    , (0xf4, "upshot"   , "virginia"   )
+    , (0xf5, "vapor"    , "visitor"    )
+    , (0xf6, "village"  , "vocalist"   )
+    , (0xf7, "virus"    , "voyager"    )
+    , (0xf8, "vulcan"   , "warranty"   )
+    , (0xf9, "waffle"   , "waterloo"   )
+    , (0xfa, "wallet"   , "whimsical"  )
+    , (0xfb, "watchword", "wichita"    )
+    , (0xfc, "wayside"  , "wilmington" )
+    , (0xfd, "willow"   , "wyoming"    )
+    , (0xfe, "woodlark" , "yesteryear" )
+    , (0xff, "zulu"     , "yucatan"    )
+    ]
diff --git a/test/Doctest.hs b/test/Doctest.hs
new file mode 100644
--- /dev/null
+++ b/test/Doctest.hs
@@ -0,0 +1,6 @@
+module Main (main) where
+
+import Test.DocTest
+
+main :: IO ()
+main = doctest ["src"]
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NumDecimals #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ParallelListComp  #-}
 
@@ -5,17 +6,18 @@
 
 
 
-import           Data.Text.PgpWordlist.Internal.Convert
-
+import           Control.DeepSeq
 import qualified Data.ByteString.Lazy                   as BSL
 import           Test.Tasty
 import qualified Test.Tasty.HUnit                       as HU
 import qualified Test.Tasty.QuickCheck                  as QC
 import           Text.Printf
-import           Data.Word
 
+import           Data.Text.PgpWordlist.Internal.Convert
+import           Data.Text.PgpWordlist.Internal.Types
 
 
+
 main :: IO ()
 main = defaultMain tree
 
@@ -31,83 +33,79 @@
 
 
 allBytesConvertible :: TestTree
-allBytesConvertible = testGroup "All bytes have a corresponding word" tests
+allBytesConvertible = HU.testCase description test
   where
-    tests = splice (map evenTest allWord8) (map oddTest allWord8)
-    allWord8 = [minBound ..] :: [Word8]
-    evenTest = testExists "%02x is convertible to an even word" toEvenWord
-    oddTest  = testExists "%02x is convertible to an odd word"  toOddWord
-    testExists msg f i = HU.testCase (printf msg i) (exists (f i))
-    exists x =  HU.assertBool "" (x `seq` True)
-
-    -- Combine two lists alternatingly
-    -- splice [1,3,5] [2,4,6,8,10] ==> [1,2,3,4,5,6,7,10]
-    splice []     ys = ys
-    splice (x:xs) ys = x : splice ys xs
+    description = "All bytes have a corresponding even/odd word"
+    assertNoBottoms x = x `deepseq` HU.assertBool "" True
+    test = assertNoBottoms (do
+        byte <- [minBound ..]
+        convert <- [unEvenWord . toEvenWord, unOddWord . toOddWord]
+        return $! convert byte )
 
 
 
 examplesBackAndForth :: TestTree
-examplesBackAndForth = testGroup "Conversion beween various examples" tests
+examplesBackAndForth = testGroup "Explicit example conversions" tests
   where
     tests = concat
-        [ [ HU.testCase (printf "#%2d: Bytes to PGP words" i)
+        [ [ HU.testCase (printf "#%d: Bytes to PGP words" i)
                         (HU.assertEqual "" (toText bytes) pgpWords)
-          , HU.testCase (printf "#%2d: PGP words to bytes" i)
+          , HU.testCase (printf "#%d: PGP words to bytes" i)
                         (HU.assertEqual "" (Right bytes) (fromText pgpWords))
           ]
         | (bytes, pgpWords) <- testCases
         | i <- [0..] :: [Int]
         ]
 
-    testCases = map (\(x,y) -> (BSL.pack x, y))
-        [ ( [0xce, 0xe7, 0x1c, 0xbf, 0xe6, 0x59, 0x49, 0x48]
-          , "spyglass truncated befriend rebellion tracker examine deckhand dictator"
-          )
-        , ( [0x06, 0x7a, 0xd2, 0xfc, 0xb7, 0x74, 0x48, 0x18]
-          , "afflict infancy standard wilmington seabird hydraulic deadbolt borderline"
-          )
-        , ( [0xb3, 0xc6, 0x75, 0x64, 0xa7, 0x9e, 0x0a, 0xbb]
-          , "scallion responsive indulge getaway repay onlooker allow publisher"
-          )
-        , ( [0x84, 0x98, 0xd3, 0x33, 0xf1, 0xe4, 0x2a, 0x92]
-          , "mural narrative stapler concurrent unwind tradition brickyard misnomer"
-          )
-        , ( [0xb2, 0x8d, 0x47, 0xf8, 0x8c, 0x57, 0xb5, 0x09]
-          , "sawdust microscope dashboard warranty offload eskimo scorecard applicant"
-          )
-        , ( [0x2e, 0x26, 0xf1, 0x24, 0x65, 0xb9, 0xae, 0xd7]
-          , "buzzard caretaker unwind capricorn fracture proximate robust stethoscope"
-          )
-        , ( [0x72, 0x19, 0x07, 0xf2, 0xca, 0x6f, 0xe4, 0xee]
-          , "highchair bottomless ahead vagabond spellbind hemisphere tonic universe"
-          )
-        , ( [0x52, 0x8f, 0x47, 0x3a, 0xbd, 0xf3, 0x64, 0x5b]
-          , "dupont midsummer dashboard corrosion skullcap vertigo flytrap exodus"
-          )
-        , ( [0xe9, 0x75, 0x73, 0x8c, 0x03, 0xc1, 0x49, 0x7f]
-          , "treadmill impartial hockey megaton acme recover deckhand integrate"
+    first f (a,b) = (f a, b) -- Bifunctor came into Base in 7.10 only
+
+    testCases = map (first BSL.pack)
+        [ ( [ 0xce, 0xe7, 0x1c, 0xbf, 0xe6, 0x59, 0x49, 0x48
+            , 0x06, 0x7a, 0xd2, 0xfc, 0xb7, 0x74, 0x48, 0x18 ]
+          , "spyglass truncated befriend rebellion tracker examine deckhand \
+            \dictator afflict infancy standard wilmington seabird hydraulic \
+            \deadbolt borderline"
           )
-        , ( [0xfd, 0xce, 0xd3, 0x8f, 0xfa, 0x3d, 0xd8, 0xf2]
-          , "willow sardonic stapler midsummer wallet crucifix stormy vagabond"
+        , ( [ 0xb3, 0xc6, 0x75, 0x64, 0xa7, 0x9e, 0x0a, 0xbb
+            , 0x84, 0x98, 0xd3, 0x33, 0xf1, 0xe4, 0x2a, 0x92 ]
+          , "scallion responsive indulge getaway repay onlooker allow \
+            \publisher mural narrative stapler concurrent unwind tradition \
+            \brickyard misnomer"
           )
-        , ( [0x2d, 0x56, 0x8c, 0x11, 0x95, 0x47, 0x4f, 0x6f]
-          , "button escapade offload babylon preclude determine dropper hemisphere"
+        , ( [ 0xb2, 0x8d, 0x47, 0xf8, 0x8c, 0x57, 0xb5, 0x09
+            , 0x2e, 0x26, 0xf1, 0x24, 0x65, 0xb9, 0xae, 0xd7 ]
+          , "sawdust microscope dashboard warranty offload eskimo scorecard \
+            \applicant buzzard caretaker unwind capricorn fracture proximate \
+            \robust stethoscope"
           )
-        , ( [0xe4, 0x05, 0x46, 0xfe, 0xc9, 0xf4, 0x41, 0x9a]
-          , "tonic almighty cubic yesteryear spearhead virginia cranky newsletter"
+        , ( [ 0x72, 0x19, 0x07, 0xf2, 0xca, 0x6f, 0xe4, 0xee
+            , 0x52, 0x8f, 0x47, 0x3a, 0xbd, 0xf3, 0x64, 0x5b ]
+          , "highchair bottomless ahead vagabond spellbind hemisphere tonic \
+            \universe dupont midsummer dashboard corrosion skullcap vertigo \
+            \flytrap exodus"
           )
-        , ( [0xb2, 0x68, 0xfc, 0xe4, 0x2c, 0xf5, 0xe5, 0x04]
-          , "sawdust gravity wayside tradition burbank visitor topmost alkali"
+        , ( [ 0xe9, 0x75, 0x73, 0x8c, 0x03, 0xc1, 0x49, 0x7f
+            , 0xfd, 0xce, 0xd3, 0x8f, 0xfa, 0x3d, 0xd8, 0xf2 ]
+          , "treadmill impartial hockey megaton acme recover deckhand \
+            \integrate willow sardonic stapler midsummer wallet crucifix \
+            \stormy vagabond"
           )
-        , ( [0xb4, 0xfb, 0xec, 0xe3, 0xc8, 0xe4, 0x29, 0xa5]
-          , "scenic wichita tumor torpedo spaniel tradition breakup paperweight"
+        , ( [ 0x2d, 0x56, 0x8c, 0x11, 0x95, 0x47, 0x4f, 0x6f
+            , 0xe4, 0x05, 0x46, 0xfe, 0xc9, 0xf4, 0x41, 0x9a ]
+          , "button escapade offload babylon preclude determine dropper \
+            \hemisphere tonic almighty cubic yesteryear spearhead virginia \
+            \cranky newsletter"
           )
-        , ( [0xbb, 0x96, 0x68, 0xc6, 0x33, 0x11, 0x4f, 0x7c]
-          , "shamrock monument frighten responsive chisel babylon dropper informant"
+        , ( [ 0xb2, 0x68, 0xfc, 0xe4, 0x2c, 0xf5, 0xe5, 0x04
+            , 0xb4, 0xfb, 0xec, 0xe3, 0xc8, 0xe4, 0x29, 0xa5 ]
+          , "sawdust gravity wayside tradition burbank visitor topmost alkali \
+            \scenic wichita tumor torpedo spaniel tradition breakup paperweight"
           )
-        , ( [0x51, 0x5e, 0x7f, 0xe3, 0x1b, 0xc0, 0x6f, 0xc7]
-          , "drunken finicky lockup torpedo beeswax recipe gremlin retraction"
+        , ( [ 0xbb, 0x96, 0x68, 0xc6, 0x33, 0x11, 0x4f, 0x7c
+            , 0x51, 0x5e, 0x7f, 0xe3, 0x1b, 0xc0, 0x6f, 0xc7 ]
+          , "shamrock monument frighten responsive chisel babylon dropper \
+            \informant drunken finicky lockup torpedo beeswax recipe gremlin \
+            \retraction"
           )
         ]
 
@@ -115,6 +113,7 @@
 randomRoundtrips = makeGroup tests
   where
     makeGroup = localOption (QC.QuickCheckMaxSize 1024)
+              . localOption (QC.QuickCheckTests 1e3)
               . testGroup "Random roundtrips"
     tests = [ QC.testProperty "Bytes -> PGP words -> Bytes" $
                 \bytes -> let bs = BSL.pack bytes
