diff --git a/COPYING b/COPYING
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,6 @@
-Copyright © 2008 Bart Massey
+Copyright © 2007 Bart Massey
+
+[This program is licensed under the "3-clause ('new') BSD License"]
 
 Redistribution and use in source and binary forms, with or
 without modification, are permitted provided that the
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,6 +1,5 @@
-# parseargs
-Command-line argument parsing for Haskell programs  
-Bart Massey <bart@cs.pdx.edu>
+# parseargs: Command-line argument parsing for Haskell programs
+Copyright (c) 2007 Bart Massey
 
 This library provides System.Console.Parseargs, a module to
 assist in argument parsing for Haskell stand-alone command
@@ -14,37 +13,60 @@
 arguments can be extracted as needed. See the Haddock
 documentation for the gory details.
 
-I have used this code with `ghc` 6 and 7 on Linux.  It is a
-fairly standard Hackage-ready package, to the extent I know
-how to construct such.
+I have used this code with `ghc` 6 and later on Linux.  It
+is a fairly standard Hackage-ready package, to the extent I
+know how to construct such.
 
-The 0.1.2 release includes a typeclass for argument types for
+This library is not what I set out to build.  It definitely
+could also use some work.  However, I use it all the time
+for writing little programs. I thought others might find it
+useful, and I also have released other code that depends on
+it, so I put it out there.
+
+Have fun with it, and let me know if there are problems.
+
+## Release History
+
+* The 0.1.2 release includes a typeclass for argument types for
 easier use.
 
-The 0.1.3 release includes more uniform and usable error
+* The 0.1.3 release includes more uniform and usable error
 handling.
 
-The various 0.1.3.x point releases include bug fixes and
+* The various 0.1.3.x point releases include bug fixes and
 various extra-minor enhancements. See the Git log.
 
-The 0.1.4 release includes the ability to mix optional and
+* The 0.1.4 release includes the ability to mix optional and
 required positional arguments.
 
-The 0.1.5 release includes the "soft dash" option, giving
+* The 0.1.5 release includes the "soft dash" option, giving
 the ability to allow positional arguments to begin with a
 dash if possible.
 
-The 0.1.5.1 release fixes some warnings and stuff.
+* The 0.1.5.1 release fixes some warnings and stuff.
 
-The 0.1.5.2 release fixes some missing documentation.
+* The 0.1.5.2 release fixes some missing documentation.
 
-This library is not what I set out to build.  It definitely
-could also use some work.  However, I use it all the time
-for writing little programs. I thought others might find it
-useful, and I also have released other code that depends on
-it, so I put it out there.
+* The 0.2 release cleans up some namespace pollution by
+removing `ArgRecord` and the `args` accessor from the public
+namespace.  This allows the use of the name `args` by the
+user to describe program arguments.
 
-Have fun with it, and let me know if there are problems.
+* The 0.2.0.1 release cleans up a bunch of documentation nits
+and cleans up copyright notices and license information.
 
-This code is released under a "3-clause BSD" license. Please
-see the file COPYING in this distribution for license terms.
+* The 0.2.0.2 release fixes the botched release of 0.2.0.1. Sigh.
+
+* The 0.2.0.3 release fixes the missing `Args` constructor
+documentation of 0.2.0.2.
+
+* The 0.2.0.4 release suppresses a GHC 7.10 warning for `Control.Monad.Safe`.
+
+* Subsequent releases are maintenance for new GHC, Cabal and
+  Stackage stuff.
+
+## License
+
+This program is licensed under the "3-clause ('new') BSD
+License".  Please see the file COPYING in this distribution
+for license terms.
diff --git a/System/Console/ParseArgs.hs b/System/Console/ParseArgs.hs
--- a/System/Console/ParseArgs.hs
+++ b/System/Console/ParseArgs.hs
@@ -1,26 +1,28 @@
-{-# LANGUAGE FlexibleInstances, DeriveDataTypeable #-}
--- Full-featured argument parsing library for Haskell programs
--- Bart Massey <bart@cs.pdx.edu>
-
--- Copyright © 2007-2010 Bart Massey
--- ALL RIGHTS RESERVED
-
--- You can redistribute and/or modify this library under the
--- terms of the "3-clause BSD LICENSE", as stated in the file
--- COPYING in the top-level directory of this distribution.
--- 
--- This library is distributed in the hope that it will be
--- useful, but WITHOUT ANY WARRANTY; without even the
--- implied warranty of MERCHANTABILITY or FITNESS FOR A
--- PARTICULAR PURPOSE.
+{-# LANGUAGE FlexibleInstances, DeriveDataTypeable, CPP #-}
+#if __GLASGOW_HASKELL__ > 720
+{-# LANGUAGE Safe #-}
+#endif
+------------------------------------------------------------
+-- |
+-- Module      :  System.Console.ParseArgs
+-- Description :  Full-featured command-line argument parsing library.
+-- Copyright   :  (c) 2007 Bart Massey
+-- License     :  BSD-style (see the file COPYING)
+-- Maintainer  :  Bart Massey <bart.massey@gmail.com>
+-- Stability   :  stable
+-- Portability :  portable
+--
+-- `ParseArgs` is a full-featured command-line argument
+-- parsing library.
+--
+-- This module supplies an argument parser.  Given a
+-- description of type [`Arg`] of the legal arguments to the
+-- program, a list of argument strings, and a bit of extra
+-- information, the `parseArgs` function in this module
+-- returns an `Args` data structure suitable for querying
+-- using the provided functions `gotArg`, `getArg`, etc.
+------------------------------------------------------------
 
--- |This module supplies an argument parser.
--- Given a description of type [`Arg`] of the legal
--- arguments to the program, a list of argument strings,
--- and a bit of extra information, the `parseArgs` function
--- in this module returns an
--- `Args` data structure suitable for querying using the
--- provided functions `gotArg`, `getArg`, etc.
 module System.Console.ParseArgs (
   -- * Describing allowed arguments
   -- |The argument parser requires a description of
@@ -31,8 +33,8 @@
   Argtype(..), 
   ArgsComplete(..),
   ArgsDash(..),
-  ArgsParseControl(..),
   APCData(..),
+  ArgsParseControl(..),
   -- ** DataArg and its pseudo-constructors
   DataArg,
   argDataRequired, argDataOptional, argDataDefaulted,
@@ -46,7 +48,7 @@
   -- |The argument parser returns an opaque map
   -- from argument index to parsed argument data
   -- (plus some convenience information).
-  ArgRecord, Args(..),
+  Args(..),
   parseArgs, parseArgsIO,
   -- ** Using parse results
   -- |Query functions permit checking for the existence
@@ -172,10 +174,12 @@
 -- |The type of the mapping from argument index to value.
 newtype ArgRecord a = ArgRecord (Map.Map a Argval)
 
--- |The data structure `parseArgs` produces.  The key
--- element is the `ArgRecord` `args`.
+-- |The data structure `parseArgs` produces. There is a should-be-hidden
+-- field that describes the parse.
 data (Ord a) => Args a =
-    Args { args :: ArgRecord a      -- ^The argument map.
+    Args { __args :: ArgRecord a    -- ^The argument parse, only listed here
+                                    -- to work around a Haddock bug. See
+                                    -- <https://github.com/haskell/haddock/issues/456>.
          , argsProgName :: String   -- ^Basename of 0th argument.
          , argsUsage :: String      -- ^Full usage string.
          , argsRest :: [ String ]   -- ^Remaining unprocessed arguments.
@@ -299,10 +303,10 @@
                                    (show k))
 
 -- |Make a keymap for looking up a flag argument.
-make_keymap :: (Ord a, Ord k, Show k) =>
-               ((Arg a) -> Maybe k)   -- ^Mapping from argdesc to flag key.
-            -> [ Arg a ]              -- ^List of argdesc.
-            -> (Map.Map k (Arg a))    -- ^Map from key to argdesc.
+make_keymap :: (Ord k, Show k) =>
+               (Arg a -> Maybe k)   -- ^Mapping from argdesc to flag key.
+            -> [Arg a]              -- ^List of argdesc.
+            -> Map.Map k (Arg a)    -- ^Map from key to argdesc.
 make_keymap f_field ads =
     (keymap_from_list .
      filter_keys .
@@ -336,13 +340,16 @@
 
 -- |Record containing the collective parse control information.
 data ArgsParseControl = ArgsParseControl {
+  -- |Level of completeness of parse.
   apcComplete :: ArgsComplete,
+  -- |Handling of dashes in parse.
   apcDash :: ArgsDash }
 
 -- |Class for building parse control information,
 -- for backward compatibility.
 class APCData a where
-  getAPCData :: a -> ArgsParseControl
+  getAPCData :: a -> ArgsParseControl  -- ^Build an 'ArgsParseControl'
+                                       -- structure from the given info.
 
 instance APCData ArgsParseControl where
   getAPCData a = a
@@ -398,7 +405,7 @@
            unless (and (map (check_present usage am) required_args))
                   (error "internal error")
            let am' = foldl supply_defaults am argd
-           return (Args { args = ArgRecord am',
+           return (Args { __args = ArgRecord am',
                           argsProgName = prog_name,
                           argsUsage = usage,
                           argsRest = rest }))
@@ -567,23 +574,26 @@
           Args a    -- ^Parsed arguments.
        -> a         -- ^Index of argument to be checked for.
        -> Bool      -- ^True if the arg was present.
-gotArg (Args { args = ArgRecord am }) k =
+gotArg (Args { __args = ArgRecord am }) k =
     case Map.lookup k am of
       Just _ -> True
       Nothing -> False
 
 -- |Type of values that can be parsed by the argument parser.
 class ArgType b where
+
     -- |Fetch an argument's value if it is present.
     getArg :: (Show a, Ord a)
            => Args a    -- ^Parsed arguments.
            -> a         -- ^Index of argument to be retrieved.
            -> Maybe b   -- ^Argument value if present.
+
     -- |Fetch the value of a required argument.
     getRequiredArg :: (Show a, Ord a)
            => Args a    -- ^Parsed arguments.
            -> a         -- ^Index of argument to be retrieved.
            -> b   -- ^Argument value.
+
     getRequiredArg ads index =
         case getArg ads index of
           Just v -> v
@@ -591,14 +601,22 @@
                           ++ show index ++ "not supplied")
 
 getArgPrimitive :: Ord a => (Argval -> Maybe b) -> Args a -> a -> Maybe b
-getArgPrimitive decons (Args { args = ArgRecord am }) k =
+getArgPrimitive decons (Args { __args = ArgRecord am }) k =
   Map.lookup k am >>= decons
 
 instance ArgType () where
-  getArg = getArgPrimitive (\ArgvalFlag -> return ())
+  getArg =
+      getArgPrimitive flagArg
+      where
+        flagArg ArgvalFlag = return ()
+        flagArg _ = error "internal error: flag arg at wrong type"
 
 instance ArgType ([] Char) where
-  getArg = getArgPrimitive (\(ArgvalString s) -> return s)
+  getArg =
+      getArgPrimitive stringArg
+      where
+        stringArg (ArgvalString s) = return s
+        stringArg _ = error "internal error: string arg at wrong type"
 
 -- |[Deprecated]  Return the `String` value, if any, of the given argument.
 getArgString :: (Show a, Ord a) =>
@@ -608,7 +626,11 @@
 getArgString = getArg
 
 instance ArgType Integer where
-  getArg = getArgPrimitive (\(ArgvalInteger i) -> return i)
+  getArg =
+      getArgPrimitive integerArg
+      where
+        integerArg (ArgvalInteger i) = return i
+        integerArg _ = error "internal error: integer arg at wrong type"
 
 -- |[Deprecated] Return the `Integer` value, if any, of the given argument.
 getArgInteger :: (Show a, Ord a) =>
@@ -618,7 +640,11 @@
 getArgInteger = getArg
 
 instance ArgType Int where
-  getArg = getArgPrimitive (\(ArgvalInt i) -> return i)
+  getArg =
+      getArgPrimitive intArg
+      where
+        intArg (ArgvalInt i) = return i
+        intArg _ = error "internal error: int arg at wrong type"
 
 -- |[Deprecated] Return the `Int` value, if any, of the given argument.
 getArgInt :: (Show a, Ord a) =>
@@ -628,7 +654,11 @@
 getArgInt = getArg
 
 instance ArgType Double where
-  getArg = getArgPrimitive (\(ArgvalDouble i) -> return i)
+  getArg =
+      getArgPrimitive doubleArg
+      where
+        doubleArg (ArgvalDouble d) = return d
+        doubleArg _ = error "internal error: double arg at wrong type"
 
 -- |[Deprecated] Return the `Double` value, if any, of the given argument.
 getArgDouble :: (Show a, Ord a) =>
@@ -638,7 +668,11 @@
 getArgDouble = getArg
 
 instance ArgType Float where
-  getArg = getArgPrimitive (\(ArgvalFloat i) -> return i)
+  getArg =
+      getArgPrimitive floatArg
+      where
+        floatArg (ArgvalFloat f) = return f
+        floatArg _ = error "internal error: float arg at wrong type"
 
 -- |[Deprecated] Return the `Float` value, if any, of the given argument.
 getArgFloat :: (Show a, Ord a) =>
diff --git a/parseargs-example.hs b/parseargs-example.hs
--- a/parseargs-example.hs
+++ b/parseargs-example.hs
@@ -1,3 +1,7 @@
+-- Copyright © 2010 Bart Massey
+-- This program is licensed under the "3-clause ('new') BSD License".
+-- Please see the file COPYING in this distribution for license terms.
+
 module Main
 where
 
@@ -49,23 +53,23 @@
 
 main :: IO ()
 main = do
-  argv <- parseArgsIO 
+  args <- parseArgsIO 
             (ArgsParseControl (ArgsTrailing "junk") ArgsSoftDash) 
             argd
   putStrLn "parse successful"
-  when (gotArg argv OptionFlag)
+  when (gotArg args OptionFlag)
        (putStrLn "saw flag")
-  case (getArg argv OptionFlagString) of
+  case (getArg args OptionFlagString) of
     Just s -> putStrLn ("saw string " ++ s)
     Nothing -> return ()
-  case (getArg argv OptionFlagInt) of
+  case (getArg args OptionFlagInt) of
     Just d -> putStrLn ("saw int " ++ (show (d::Int)))
     Nothing -> return ()
-  case (getArg argv OptionPreoptional) of
+  case (getArg args OptionPreoptional) of
     Just s -> putStrLn ("saw pre-optional " ++ s)
     Nothing -> return ()
-  putStrLn ("saw fixed " ++ (fromJust (getArgString argv OptionFixed)))
-  case (getArg argv OptionOptional) of
+  putStrLn ("saw fixed " ++ (fromJust (getArgString args OptionFixed)))
+  case (getArg args OptionOptional) of
     Just s -> putStrLn ("saw optional " ++ s)
     Nothing -> return ()
-  putStrLn ("saw rest: " ++ show (argsRest argv))
+  putStrLn ("saw rest: " ++ show (argsRest args))
diff --git a/parseargs.cabal b/parseargs.cabal
--- a/parseargs.cabal
+++ b/parseargs.cabal
@@ -1,28 +1,41 @@
+-- Copyright © 2010 Bart Massey
+-- This work is licensed under the "3-clause ('new') BSD License".
+-- Please see the file COPYING in this distribution for license terms.
+
 Name: parseargs
 Build-Type: Simple
-Description: Parse command-line arguments
+Description: Full-featured command-line argument parsing library.
 -- Don't forget to bump the source-repository this below
-Version: 0.1.5.2
-Cabal-Version: >= 1.6
+Version: 0.2.0.9
+Cabal-Version: >= 1.8
 License: BSD3
 License-File: COPYING
 Author: Bart Massey <bart@cs.pdx.edu>
-Copyright: Copyright (C) 2008 Bart Massey
+Copyright: Copyright (c) 2007 Bart Massey
 Maintainer: Bart Massey <bart@cs.pdx.edu>
 Homepage: http://github.com/BartMassey/parseargs
 Category: Console
-Synopsis: Command-line argument parsing library for Haskell programs
-Extra-Source-Files: README.md
+Synopsis: Parse command-line arguments
+Extra-Source-Files: README.md test-parseargs.sh tests/*.in tests/*.out
+Tested-With: GHC >= 6 && <= 8.4.4
 
 Library
   Build-Depends:   base < 5, containers < 1
   Exposed-Modules: System.Console.ParseArgs
+  GHC-Options:     -Wall
 
 Executable parseargs-example
-  Build-Depends:   base < 5
+  Build-Depends:   base < 5, containers < 1
   Main-Is:         parseargs-example.hs
   Other-Modules:   System.Console.ParseArgs
+  GHC-Options:     -Wall
 
+Test-Suite test-parseargs
+  Type:            exitcode-stdio-1.0
+  Main-Is:         test-parseargs.hs
+  build-depends:   base < 5, process < 2
+  build-tool-depends: parseargs:parseargs-example
+
 Source-repository head
   Type:     git
   Location: git://github.com/BartMassey/parseargs.git
@@ -30,4 +43,4 @@
 Source-repository this
   Type:     git
   Location: git://github.com/BartMassey/parseargs.git
-  Tag:      v0.1.5.2
+  Tag:      v0.2.0.9
diff --git a/test-parseargs.hs b/test-parseargs.hs
new file mode 100644
--- /dev/null
+++ b/test-parseargs.hs
@@ -0,0 +1,11 @@
+-- Stupid glue for "cabal test"
+-- http://stackoverflow.com/a/31214045/364875
+
+import System.Exit
+import System.Process
+
+main = do
+  result <- system "./test-parseargs.sh"
+  case result of
+    ExitSuccess -> return ()
+    _ -> exitFailure
diff --git a/test-parseargs.sh b/test-parseargs.sh
new file mode 100644
--- /dev/null
+++ b/test-parseargs.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+# Copyright © 2016 Bart Massey
+# Run simple parseargs tests
+PA=parseargs-example
+TMP=/tmp/test-parseargs-$$
+trap "rm -f $TMP" 0 1 2 3 15
+for f in tests/*.in
+do
+    T="`basename $f .in`"
+    $PA `cat $f` >$TMP
+    if ! cmp $TMP tests/$T.out
+    then
+        echo "test $T failed"
+        echo "expected:"
+        cat tests/$T.out
+        echo "got:"
+        cat $TMP
+        exit 1
+    fi
+done
+exit 0
diff --git a/tests/t1.in b/tests/t1.in
new file mode 100644
--- /dev/null
+++ b/tests/t1.in
@@ -0,0 +1,1 @@
+x
diff --git a/tests/t1.out b/tests/t1.out
new file mode 100644
--- /dev/null
+++ b/tests/t1.out
@@ -0,0 +1,4 @@
+parse successful
+saw int 7
+saw fixed x
+saw rest: []
diff --git a/tests/t2.in b/tests/t2.in
new file mode 100644
--- /dev/null
+++ b/tests/t2.in
@@ -0,0 +1,1 @@
+x y
diff --git a/tests/t2.out b/tests/t2.out
new file mode 100644
--- /dev/null
+++ b/tests/t2.out
@@ -0,0 +1,5 @@
+parse successful
+saw int 7
+saw pre-optional x
+saw fixed y
+saw rest: []
diff --git a/tests/t3.in b/tests/t3.in
new file mode 100644
--- /dev/null
+++ b/tests/t3.in
@@ -0,0 +1,1 @@
+x y z
diff --git a/tests/t3.out b/tests/t3.out
new file mode 100644
--- /dev/null
+++ b/tests/t3.out
@@ -0,0 +1,6 @@
+parse successful
+saw int 7
+saw pre-optional x
+saw fixed y
+saw optional z
+saw rest: []
