diff --git a/Options/Applicative/Builder.hs b/Options/Applicative/Builder.hs
--- a/Options/Applicative/Builder.hs
+++ b/Options/Applicative/Builder.hs
@@ -1,24 +1,21 @@
-{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE DeriveFunctor, EmptyDataDecls #-}
 module Options.Applicative.Builder (
   -- * Parser builders
   --
   -- | This module contains utility functions and combinators to create parsers
   -- for individual options.
   --
-  -- Each parser builder takes an option modifier, which can be specified by
-  -- composing basic modifiers using '&' and 'idm' (which are just convenient
-  -- synonyms for the 'Category' operations 'Control.Category.>>>' and
-  -- 'Control.Category.id').
+  -- Each parser builder takes an option modifier. A modifier can be created by
+  -- composing the basic modifiers provided by this module using the 'Monoid'
+  -- operations 'mempty' and 'mappend', or their aliases 'idm' and '&'.
   --
   -- For example:
   --
-  --
   -- > out = strOption
   -- >     ( long "output"
   -- >     & short 'o'
   -- >     & metavar "FILENAME" )
   --
-  --
   -- creates a parser for an option called \"output\".
   subparser,
   argument,
@@ -39,7 +36,6 @@
   reader,
   hidden,
   internal,
-  transform,
   command,
   idm,
   (&),
@@ -74,64 +70,55 @@
   ) where
 
 import Control.Applicative
-import Control.Category
 import Control.Monad
-import Data.Functor.Identity
-import Data.Lens.Common
+import Data.Maybe
+import Data.Monoid
 
 import Options.Applicative.Common
 import Options.Applicative.Types
 
-import Prelude hiding (id, (.))
-
 data OptionFields a = OptionFields
-  { _optNames :: [OptName]
-  , _optReader :: String -> Maybe a }
+  { optNames :: [OptName]
+  , optReader :: String -> Maybe a }
   deriving Functor
 
 data FlagFields a = FlagFields
-  { _flagNames :: [OptName]
-  , _flagActive :: a }
+  { flagNames :: [OptName]
+  , flagActive :: a }
   deriving Functor
 
 data CommandFields a = CommandFields
-  { _cmdCommands :: [(String, ParserInfo a)] }
+  { cmdCommands :: [(String, ParserInfo a)] }
   deriving Functor
 
-optNames :: Lens (OptionFields a) [OptName]
-optNames = lens _optNames $ \x o -> o { _optNames = x }
-
-optReader :: Lens (OptionFields a) (String -> Maybe a)
-optReader = lens _optReader $ \x o -> o { _optReader = x }
-
-flagNames :: Lens (FlagFields a) [OptName]
-flagNames = lens _flagNames $ \x o -> o { _flagNames = x }
-
-cmdCommands :: Lens (CommandFields a) [(String, ParserInfo a)]
-cmdCommands = lens _cmdCommands $ \x o -> o { _cmdCommands = x }
+data ArgumentFields a
+  deriving Functor
 
 class HasName f where
   name :: OptName -> f a -> f a
 
 instance HasName OptionFields where
-  name n = modL optNames (n:)
+  name n fields = fields { optNames = n : optNames fields }
 
 instance HasName FlagFields where
-  name n = modL flagNames (n:)
+  name n fields = fields { flagNames = n : flagNames fields }
 
 -- mod --
 
-data Mod f a b = Mod (f a -> f b) (OptProperties a -> OptProperties b)
+data Mod f a = Mod (f a -> f a)
+                   (Maybe a)
+                   (OptProperties -> OptProperties)
 
-optionMod :: (OptProperties a -> OptProperties a) -> Mod f a a
-optionMod = Mod id
+optionMod :: (OptProperties -> OptProperties) -> Mod f a
+optionMod = Mod id Nothing
 
-fieldMod :: (f a -> f a) -> Mod f a a
-fieldMod f = Mod f id
+fieldMod :: (f a -> f a) -> Mod f a
+fieldMod f = Mod f Nothing id
 
-instance Category (Mod f) where
-  id = Mod id id
-  Mod f1 g1 . Mod f2 g2 = Mod (f1 . f2) (g1 . g2)
+instance Monoid (Mod f a) where
+  mempty = Mod id Nothing id
+  Mod f1 d1 g1 `mappend` Mod f2 d2 g2
+    = Mod (f2 . f1) (d2 `mplus` d1) (g2 . g1)
 
 -- readers --
 
@@ -152,75 +139,67 @@
 -- modifiers --
 
 -- | Specify a short name for an option.
-short :: HasName f => Char -> Mod f a a
+short :: HasName f => Char -> Mod f a
 short = fieldMod . name . OptShort
 
 -- | Specify a long name for an option.
-long :: HasName f => String -> Mod f a a
+long :: HasName f => String -> Mod f a
 long = fieldMod . name . OptLong
 
--- | Specify a default value for an option.
-value :: a -> Mod f a a
-value = optionMod . setL propDefault . Just
+---- | Specify a default value for an option.
+value :: a -> Mod f a
+value x = Mod id (Just x) id
 
 -- | Specify the help text for an option.
-help :: String -> Mod f a a
-help = optionMod . setL propHelp
+help :: String -> Mod f a
+help s = optionMod $ \p -> p { propHelp = s }
 
 -- | Specify the 'Option' reader.
-reader :: (String -> Maybe a) -> Mod OptionFields a a
-reader = fieldMod . setL optReader
+reader :: (String -> Maybe a) -> Mod OptionFields a
+reader f = fieldMod $ \p -> p { optReader = f }
 
 -- | Specify the metavariable.
-metavar :: String -> Mod f a a
-metavar = optionMod . setL propMetaVar
+metavar :: String -> Mod f a
+metavar var = optionMod $ \p -> p { propMetaVar = var }
 
 -- | Hide this option from the brief description.
-hidden :: Mod f a a
-hidden = optionMod $ propVisibility ^%= min Hidden
+hidden :: Mod f a
+hidden = optionMod $ \p ->
+  p { propVisibility = min Hidden (propVisibility p) }
 
 -- | Hide this option from the help text
-internal :: Mod f a a
-internal = optionMod $ propVisibility ^= Internal
-
--- | Apply a transformation to the return value of this option.
---
--- This can be used, for example, to provide a default value for
--- a required option, like:
---
--- >strOption
--- >( transform Just
--- >& value Nothing )
-transform :: Functor f => (a -> b) -> Mod f a b
-transform f = Mod (fmap f) (fmap f)
+internal :: Mod f a
+internal = optionMod $ \p -> p { propVisibility = Internal }
 
 -- | Add a command to a subparser option.
-command :: String -> ParserInfo a -> Mod CommandFields a a
-command cmd pinfo = fieldMod $ cmdCommands^%=((cmd, pinfo):)
+command :: String -> ParserInfo a -> Mod CommandFields a
+command cmd pinfo = fieldMod $ \p ->
+  p { cmdCommands = (cmd, pinfo) : cmdCommands p }
 
 -- parsers --
 
 -- | Base default properties.
-baseProps :: OptProperties a
+baseProps :: OptProperties
 baseProps = OptProperties
-  { _propMetaVar = ""
-  , _propVisibility = Visible
-  , _propHelp = ""
-  , _propDefault = Nothing }
+  { propMetaVar = ""
+  , propVisibility = Visible
+  , propHelp = "" }
 
+mkOption :: Maybe a -> Option a -> Parser a
+mkOption def opt = liftOpt opt <|> maybe empty pure def
+
 -- | Builder for a command parser. The 'command' modifier can be used to
 -- specify individual commands.
-subparser :: Mod CommandFields a b -> Parser b
-subparser m = liftOpt $ Option rdr (g baseProps)
+subparser :: Mod CommandFields a -> Parser a
+subparser m = mkOption def $ Option rdr (g baseProps)
   where
-    Mod f g = m . metavar "COMMAND"
+    Mod f def g = m & metavar "COMMAND"
     CommandFields cmds = f (CommandFields [])
     rdr = CmdReader (map fst cmds) (`lookup` cmds)
 
 -- | Builder for an argument parser.
-argument :: (String -> Maybe a) -> Mod Identity a b -> Parser b
-argument p (Mod f g) = liftOpt $ Option (ArgReader p') (g baseProps)
-  where p' s = fmap (runIdentity . f . Identity) (p s)
+argument :: (String -> Maybe a) -> Mod ArgumentFields a -> Parser a
+argument p (Mod _ def g) = mkOption def $ Option (ArgReader p) (g baseProps)
 
 -- | Builder for an argument list parser. All arguments are collected and
 -- returned as a list.
@@ -230,9 +209,11 @@
 -- This parser accepts a special argument: @--@. When a @--@ is found on the
 -- command line, all following arguments are included in the result, even if
 -- they start with @'-'@.
-arguments :: (String -> Maybe a) -> Mod Identity a b -> Parser [b]
-arguments p m = args
+arguments :: (String -> Maybe a) -> Mod ArgumentFields [a] -> Parser [a]
+arguments p m = args1 <|> pure (fromMaybe [] def)
   where
+    Mod _ def g = m
+
     p' ('-':_) = Nothing
     p' s = p s
 
@@ -241,8 +222,8 @@
       Just a -> fmap (a:) args
     args = args1 <|> pure []
 
-    arg' = argument p' m
-    arg = argument p m
+    arg' = argument p' (optionMod g)
+    arg = argument p (optionMod g)
 
     ddash = argument (guard . (== "--")) internal
 
@@ -252,9 +233,9 @@
 -- encountered. For a simple boolean value, use `switch` instead.
 flag :: a                         -- ^ default value
      -> a                         -- ^ active value
-     -> Mod FlagFields a b        -- ^ option modifier
-     -> Parser b
-flag defv actv m = flag' actv (m . value defv)
+     -> Mod FlagFields a          -- ^ option modifier
+     -> Parser a
+flag defv actv m = flag' actv m <|> pure defv
 
 -- | Builder for a flag parser without a default value.
 --
@@ -267,103 +248,98 @@
 --
 -- is a parser that counts the number of "-t" arguments on the command line.
 flag' :: a                         -- ^ active value
-      -> Mod FlagFields a b        -- ^ option modifier
-      -> Parser b
-flag' actv (Mod f g) = liftOpt $ Option rdr (g baseProps)
+      -> Mod FlagFields a          -- ^ option modifier
+      -> Parser a
+flag' actv (Mod f def g) = mkOption def $ Option rdr (g baseProps)
   where
-    rdr = let FlagFields ns actv' = f (FlagFields [] actv)
-          in FlagReader ns actv'
+    rdr = let fields = f (FlagFields [] actv)
+          in FlagReader (flagNames fields)
+                        (flagActive fields)
 
 -- | Builder for a boolean flag.
 --
 -- > switch = flag False True
-switch :: Mod FlagFields Bool a -> Parser a
+switch :: Mod FlagFields Bool -> Parser Bool
 switch = flag False True
 
 -- | Builder for an option with a null reader. A non-trivial reader can be
 -- added using the 'reader' modifier.
-nullOption :: Mod OptionFields a b -> Parser b
-nullOption (Mod f g) = liftOpt $ Option rdr (g baseProps)
+nullOption :: Mod OptionFields a -> Parser a
+nullOption (Mod f def g) = mkOption def $ Option rdr (g baseProps)
   where
     rdr = let fields = f (OptionFields [] disabled)
-          in OptReader (fields^.optNames) (fields^.optReader)
+          in OptReader (optNames fields) (optReader fields)
 
 -- | Builder for an option taking a 'String' argument.
-strOption :: Mod OptionFields String a -> Parser a
-strOption m = nullOption $ m . reader str
+strOption :: Mod OptionFields String -> Parser String
+strOption m = nullOption $ m & reader str
 
 -- | Builder for an option using the 'auto' reader.
-option :: Read a => Mod OptionFields a b -> Parser b
-option m = nullOption $ m . reader auto
+option :: Read a => Mod OptionFields a -> Parser a
+option m = nullOption $ m & reader auto
 
 -- | Modifier for 'ParserInfo'.
-newtype InfoMod a b = InfoMod
-  { applyInfoMod :: ParserInfo a -> ParserInfo b }
+newtype InfoMod a = InfoMod
+  { applyInfoMod :: ParserInfo a -> ParserInfo a }
 
-instance Category InfoMod where
-  id = InfoMod id
-  m1 . m2 = InfoMod $ applyInfoMod m1 . applyInfoMod m2
+instance Monoid (InfoMod a) where
+  mempty = InfoMod id
+  mappend m1 m2 = InfoMod $ applyInfoMod m2 . applyInfoMod m1
 
 -- | Specify a full description for this parser.
-fullDesc :: InfoMod a a
-fullDesc = InfoMod $ infoFullDesc^=True
+fullDesc :: InfoMod a
+fullDesc = InfoMod $ \i -> i { infoFullDesc = True }
 
 -- | Specify a header for this parser.
-header :: String -> InfoMod a a
-header s = InfoMod $ infoHeader^=s
+header :: String -> InfoMod a
+header s = InfoMod $ \i -> i { infoHeader = s }
 
 -- | Specify a footer for this parser.
-footer :: String -> InfoMod a a
-footer s = InfoMod $ infoFooter^=s
+footer :: String -> InfoMod a
+footer s = InfoMod $ \i -> i { infoFooter = s }
 
 -- | Specify a short program description.
-progDesc :: String -> InfoMod a a
-progDesc s = InfoMod $ infoProgDesc^=s
+progDesc :: String -> InfoMod a
+progDesc s = InfoMod $ \i -> i { infoProgDesc = s }
 
 -- | Specify an exit code if a parse error occurs.
-failureCode :: Int -> InfoMod a a
-failureCode n = InfoMod $ infoFailureCode^=n
+failureCode :: Int -> InfoMod a
+failureCode n = InfoMod $ \i -> i { infoFailureCode = n }
 
 -- | Create a 'ParserInfo' given a 'Parser' and a modifier.
-info :: Parser a -> InfoMod a a -> ParserInfo a
+info :: Parser a -> InfoMod a -> ParserInfo a
 info parser m = applyInfoMod m base
   where
     base = ParserInfo
-      { _infoParser = parser
-      , _infoDesc = ParserDesc
-        { _descFull = True
-        , _descProg = ""
-        , _descHeader = ""
-        , _descFooter = ""
-        , _descFailureCode = 1
-        }
-      }
-
-newtype PrefsModC a b = PrefsMod
-  { applyPrefsMod :: a -> b }
-  -- this newtype is just to define a Category instance, for consistency with
-  -- the other modifiers; we're only going to use it with a = b = ParserPrefs
+      { infoParser = parser
+      , infoFullDesc = True
+      , infoProgDesc = ""
+      , infoHeader = ""
+      , infoFooter = ""
+      , infoFailureCode = 1 }
 
--- | Modifier for 'ParserPrefs'.
-type PrefsMod = PrefsModC ParserPrefs ParserPrefs
+newtype PrefsMod = PrefsMod
+  { applyPrefsMod :: ParserPrefs -> ParserPrefs }
 
-instance Category PrefsModC where
-  id = PrefsMod id
-  m1 . m2 = PrefsMod $ applyPrefsMod m1 . applyPrefsMod m2
+instance Monoid PrefsMod where
+  mempty = PrefsMod id
+  mappend m1 m2 = PrefsMod $ applyPrefsMod m2 . applyPrefsMod m1
 
 multiSuffix :: String -> PrefsMod
-multiSuffix s = PrefsMod $ prefMultiSuffix ^= s
+multiSuffix s = PrefsMod $ \p -> p { prefMultiSuffix = s }
 
 prefs :: PrefsMod -> ParserPrefs
 prefs m = applyPrefsMod m base
   where
     base = ParserPrefs
-      { _prefMultiSuffix = "" }
+      { prefMultiSuffix = "" }
 
--- | Trivial option modifier.
-idm :: Category hom => hom a a
-idm = id
+-- convenience shortcuts
 
--- | Compose modifiers.
-(&) :: Category hom => hom a b -> hom b c -> hom a c
-(&) = flip (.)
+--- | Trivial option modifier.
+idm :: Monoid m => m
+idm = mempty
+
+--- | Compose modifiers.
+(&) :: Monoid m => m -> m -> m
+(&) = mappend
diff --git a/Options/Applicative/Common.hs b/Options/Applicative/Common.hs
--- a/Options/Applicative/Common.hs
+++ b/Options/Applicative/Common.hs
@@ -50,7 +50,6 @@
 import Control.Monad.Trans.Class
 import Control.Monad.Trans.Error
 import Control.Monad.Trans.Writer
-import Data.Lens.Common
 import Data.Maybe
 import Data.Monoid
 import Options.Applicative.Types
@@ -100,7 +99,7 @@
     | Just subp <- f arg
     -> Just $ \args -> do
           setContext (Just arg) subp
-          runParser (subp^.infoParser) args
+          runParser (infoParser subp) args
   _ -> Nothing
   where
     parsed
@@ -127,7 +126,7 @@
 stepParser :: Parser a -> String -> [String] -> P (Parser a, [String])
 stepParser (NilP _) _ _ = empty
 stepParser (OptP opt) arg args
-  | Just matcher <- optMatches (opt ^. optMain) arg
+  | Just matcher <- optMatches (optMain opt) arg
   = do (r, args') <- matcher args
        return (pure r, args')
   | otherwise = empty
@@ -171,7 +170,7 @@
 -- the options don't have a default value.
 evalParser :: Parser a -> P a
 evalParser (NilP r) = tryP r
-evalParser (OptP opt) = tryP (opt ^. optDefault)
+evalParser (OptP _) = empty
 evalParser (MultP p1 p2) = evalParser p1 <*> evalParser p2
 evalParser (AltP p1 p2) = evalParser p1 <|> evalParser p2
 evalParser (BindP p k) = evalParser p >>= evalParser . k
@@ -192,8 +191,7 @@
        -> (forall x . OptHelpInfo -> Option x -> b)
        -> Parser a -> [b]
     go _ _ _ (NilP _) = []
-    go m d f (OptP opt) = [f (OptHelpInfo m d') opt]
-      where d' = d || isJust (opt^.optDefault)
+    go m d f (OptP opt) = [f (OptHelpInfo m d) opt]
     go m d f (MultP p1 p2) = go m d f p1 ++ go m d f p2
     go m d f (AltP p1 p2) = go m d' f p1 ++ go m d' f p2
       where d' = d || has_default p1 || has_default p2
diff --git a/Options/Applicative/Extra.hs b/Options/Applicative/Extra.hs
--- a/Options/Applicative/Extra.hs
+++ b/Options/Applicative/Extra.hs
@@ -10,7 +10,6 @@
   ParserFailure(..),
   ) where
 
-import Data.Lens.Common
 import Options.Applicative.Common
 import Options.Applicative.Builder
 import Options.Applicative.Help
@@ -61,16 +60,17 @@
                  parserHelpText pprefs
                . add_error msg
                . add_usage name progn
-      , errExitCode = ExitFailure (pinfo^.infoFailureCode) }
+      , errExitCode = ExitFailure (infoFailureCode pinfo) }
   where
-    parser = pinfo^.infoParser
-    add_usage name progn i =
-      modL infoHeader
-           (\h -> vcat [h, usage pprefs (i^.infoParser) ename])
-           i
+    parser = infoParser pinfo
+    add_usage name progn i = i
+      { infoHeader = vcat
+          [ infoHeader i
+          , usage pprefs (infoParser i) ename ] }
       where
         ename = maybe progn (\n -> progn ++ " " ++ n) name
-    add_error msg = modL infoHeader $ \h -> vcat [msg, h]
+    add_error msg i = i
+      { infoHeader = vcat [msg, infoHeader i] }
 
     with_context :: Context
                  -> ParserInfo a
diff --git a/Options/Applicative/Help.hs b/Options/Applicative/Help.hs
--- a/Options/Applicative/Help.hs
+++ b/Options/Applicative/Help.hs
@@ -6,7 +6,6 @@
   parserHelpText,
   ) where
 
-import Data.Lens.Common
 import Data.List
 import Data.Maybe
 import Options.Applicative.Common
@@ -26,18 +25,18 @@
 -- | Generate description for a single option.
 optDesc :: ParserPrefs -> OptDescStyle -> OptHelpInfo -> Option a -> String
 optDesc pprefs style info opt =
-  let ns = optionNames $ opt^.optMain
-      mv = opt^.optMetaVar
+  let ns = optionNames $ optMain opt
+      mv = optMetaVar opt
       descs = map showOption (sort ns)
       desc' = intercalate (descSep style) descs <+> mv
       show_opt
-        | opt^.optVisibility == Hidden
+        | optVisibility opt == Hidden
         = descHidden style
         | otherwise
-        = opt^.optVisibility == Visible
+        = optVisibility opt == Visible
       suffix
         | hinfoMulti info
-        = pprefs^.prefMultiSuffix
+        = prefMultiSuffix pprefs
         | otherwise
         = ""
       render text
@@ -58,10 +57,10 @@
 cmdDesc = concat . mapParser desc
   where
     desc _ opt
-      | CmdReader cmds p <- opt^.optMain
+      | CmdReader cmds p <- optMain opt
       = tabulate [(cmd, d)
                  | cmd <- cmds
-                 , d <- maybeToList . fmap (getL infoProgDesc) $ p cmd ]
+                 , d <- maybeToList . fmap infoProgDesc $ p cmd ]
       | otherwise
       = []
 
@@ -83,7 +82,7 @@
       | null h = Nothing
       | otherwise = Just (n, h)
       where n = optDesc pprefs style info opt
-            h = opt^.optHelp
+            h = optHelp opt
     style = OptDescStyle
       { descSep = ","
       , descHidden = True
@@ -92,18 +91,18 @@
 -- | Generate the help text for a program.
 parserHelpText :: ParserPrefs -> ParserInfo a -> String
 parserHelpText pprefs pinfo = unlines
-   $ nn [pinfo^.infoHeader]
-  ++ [ "  " ++ line | line <- nn [pinfo^.infoProgDesc] ]
+   $ nn [infoHeader pinfo]
+  ++ [ "  " ++ line | line <- nn [infoProgDesc pinfo] ]
   ++ [ line | let opts = fullDesc pprefs p
             , not (null opts)
-            , line <- ["", "Common options:"] ++ opts
-            , pinfo^.infoFullDesc ]
+            , line <- ["", "Available options:"] ++ opts
+            , infoFullDesc pinfo ]
   ++ [ line | let cmds = cmdDesc p
             , not (null cmds)
             , line <- ["", "Available commands:"] ++ cmds
-            , pinfo^.infoFullDesc ]
-  ++ [ line | footer <- nn [pinfo^.infoFooter]
+            , infoFullDesc pinfo ]
+  ++ [ line | footer <- nn [infoFooter pinfo]
             , line <- ["", footer] ]
   where
     nn = filter (not . null)
-    p = pinfo^.infoParser
+    p = infoParser pinfo
diff --git a/Options/Applicative/Types.hs b/Options/Applicative/Types.hs
--- a/Options/Applicative/Types.hs
+++ b/Options/Applicative/Types.hs
@@ -1,25 +1,10 @@
 {-# LANGUAGE GADTs, DeriveFunctor #-}
 module Options.Applicative.Types (
   ParserInfo(..),
-  ParserDesc(..),
   ParserPrefs(..),
   Context(..),
   P,
 
-  infoParser,
-  infoDesc,
-  infoFullDesc,
-  infoProgDesc,
-  infoHeader,
-  infoFooter,
-  infoFailureCode,
-
-  descFull,
-  descProg,
-  descHeader,
-  descFooter,
-  descFailureCode,
-
   Option(..),
   OptName(..),
   OptReader(..),
@@ -29,16 +14,9 @@
   ParserFailure(..),
   OptHelpInfo(..),
 
-  optMain,
-  optDefault,
   optVisibility,
-  optHelp,
   optMetaVar,
-  propDefault,
-  propVisibility,
-  propHelp,
-  propMetaVar,
-  prefMultiSuffix,
+  optHelp
   ) where
 
 import Control.Applicative
@@ -46,29 +24,23 @@
 import Control.Monad
 import Control.Monad.Trans.Error
 import Control.Monad.Trans.Writer
-import Data.Lens.Common
 import Data.Monoid
 import Prelude hiding ((.), id)
 import System.Exit
 
 -- | A full description for a runnable 'Parser' for a program.
 data ParserInfo a = ParserInfo
-  { _infoParser :: Parser a            -- ^ the option parser for the program
-  , _infoDesc :: ParserDesc            -- ^ description of the parser
+  { infoParser :: Parser a            -- ^ the option parser for the program
+  , infoFullDesc :: Bool              -- ^ whether the help text should contain full documentation
+  , infoProgDesc :: String            -- ^ brief parser description
+  , infoHeader :: String              -- ^ header of the full parser description
+  , infoFooter :: String              -- ^ footer of the full parser description
+  , infoFailureCode :: Int            -- ^ exit code for a parser failure
   } deriving Functor
 
--- | Attributes that can be associated to a 'Parser'.
-data ParserDesc = ParserDesc
-  { _descFull:: Bool              -- ^ whether the help text should contain full documentation
-  , _descProg:: String            -- ^ brief parser description
-  , _descHeader :: String         -- ^ header of the full parser description
-  , _descFooter :: String         -- ^ footer of the full parser description
-  , _descFailureCode :: Int       -- ^ exit code for a parser failure
-  }
-
 -- | Global preferences for a top-level 'Parser'.
 data ParserPrefs = ParserPrefs
-  { _prefMultiSuffix :: String    -- ^ metavar suffix for multiple options
+  { prefMultiSuffix :: String    -- ^ metavar suffix for multiple options
   }
 
 data Context where
@@ -94,19 +66,17 @@
   deriving (Eq, Ord)
 
 -- | Specification for an individual parser option.
-data OptProperties a = OptProperties
-  { _propDefault :: Maybe a                -- ^ default value
-  , _propVisibility :: OptVisibility       -- ^ whether this flag is shown is the brief description
-  , _propHelp :: String                    -- ^ help text for this option
-  , _propMetaVar :: String                 -- ^ metavariable for this option
-  } deriving Functor
+data OptProperties = OptProperties
+  { propVisibility :: OptVisibility       -- ^ whether this flag is shown is the brief description
+  , propHelp :: String                    -- ^ help text for this option
+  , propMetaVar :: String                 -- ^ metavariable for this option
+  }
 
 -- | A single option of a parser.
 data Option a = Option
-  { _optMain :: OptReader a               -- ^ reader for this option
-  , _optProps :: OptProperties a          -- ^ properties of this option
-  }
-  deriving Functor
+  { optMain :: OptReader a               -- ^ reader for this option
+  , optProps :: OptProperties            -- ^ properties of this option
+  } deriving Functor
 
 -- | An 'OptReader' defines whether an option matches an command line argument.
 data OptReader a
@@ -157,73 +127,11 @@
   { hinfoMulti :: Bool
   , hinfoDefault :: Bool }
 
--- lenses
-
-optMain :: Lens (Option a) (OptReader a)
-optMain = lens _optMain $ \x o -> o { _optMain = x }
-
-optProps :: Lens (Option a) (OptProperties a)
-optProps = lens _optProps $ \x o -> o { _optProps = x }
-
-propDefault :: Lens (OptProperties a) (Maybe a)
-propDefault = lens _propDefault $ \x o -> o { _propDefault = x }
-
-propVisibility :: Lens (OptProperties a) OptVisibility
-propVisibility = lens _propVisibility $ \x o -> o { _propVisibility = x }
-
-propHelp :: Lens (OptProperties a) String
-propHelp = lens _propHelp $ \x o -> o { _propHelp = x }
-
-propMetaVar :: Lens (OptProperties a) String
-propMetaVar = lens _propMetaVar $ \x o -> o { _propMetaVar = x }
-
-optDefault :: Lens (Option a) (Maybe a)
-optDefault = propDefault . optProps
-
-optVisibility :: Lens (Option a) OptVisibility
+optVisibility :: Option a -> OptVisibility
 optVisibility = propVisibility . optProps
 
-optHelp :: Lens (Option a) String
-optHelp = propHelp . optProps
+optHelp :: Option a -> String
+optHelp  = propHelp . optProps
 
-optMetaVar :: Lens (Option a) String
+optMetaVar :: Option a -> String
 optMetaVar = propMetaVar . optProps
-
-descFull :: Lens ParserDesc Bool
-descFull = lens _descFull $ \x p -> p { _descFull = x }
-
-descProg :: Lens ParserDesc String
-descProg = lens _descProg $ \x p -> p { _descProg = x }
-
-descHeader :: Lens ParserDesc String
-descHeader = lens _descHeader $ \x p -> p { _descHeader = x }
-
-descFooter :: Lens ParserDesc String
-descFooter = lens _descFooter $ \x p -> p { _descFooter = x }
-
-descFailureCode :: Lens ParserDesc Int
-descFailureCode = lens _descFailureCode $ \x p -> p { _descFailureCode = x }
-
-infoParser :: Lens (ParserInfo a) (Parser a)
-infoParser = lens _infoParser $ \x p -> p { _infoParser = x }
-
-infoDesc :: Lens (ParserInfo a) ParserDesc
-infoDesc = lens _infoDesc $ \x p -> p { _infoDesc = x }
-
-infoFullDesc :: Lens (ParserInfo a) Bool
-infoFullDesc = descFull . infoDesc
-
-infoProgDesc :: Lens (ParserInfo a) String
-infoProgDesc = descProg . infoDesc
-
-infoHeader :: Lens (ParserInfo a) String
-infoHeader = descHeader . infoDesc
-
-infoFooter :: Lens (ParserInfo a) String
-infoFooter = descFooter . infoDesc
-
-infoFailureCode :: Lens (ParserInfo a) Int
-infoFailureCode = descFailureCode . infoDesc
-
-prefMultiSuffix :: Lens ParserPrefs String
-prefMultiSuffix = lens _prefMultiSuffix $ \x p -> p { _prefMultiSuffix = x }
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -59,7 +59,7 @@
     Usage: hello --hello TARGET [--quiet]
       Print a greeting for TARGET
 
-    Common options:
+    Available options:
       -h,--help                Show this help text
       --hello TARGET           Target for the greeting
       --quiet                  Whether to be quiet
@@ -198,7 +198,7 @@
 creates an argument accepting any string.
 
 Arguments are only displayed in the brief help text, so there's no need to
-attach a description to them. They should manually documented in the program
+attach a description to them. They should be manually documented in the program
 description.
 
 ### Commands
@@ -216,10 +216,10 @@
 
 ```haskell
 subparser
-( command "add" (info addOptions)
-    ( progDesc "Add a file to the repository" )
-& command "commit") (info commitOptions)
-    ( progDesc "Record changes to the repository" )
+( command "add" (info addOptions
+    ( progDesc "Add a file to the repository" ))
+& command "commit" (info commitOptions
+    ( progDesc "Record changes to the repository" ))
 )
 ```
 
@@ -233,17 +233,33 @@
 
 ```haskell
 data Options = Options
-  { globalOpt :: String
-  , globalFlag :: Bool
+  { optGlobalOpt :: String
+  , optGlobalFlag :: Bool
   ...
-  , commandOpts :: CommandOptions }
+  , optCommand :: Command }
 
-data CommandOptions
-  = AddOptions { ... }
-  | CommitOptions { ... }
+data Command
+  = Add AddOptions
+  | Commit CommitOptions
   ...
 ```
 
+Alternatively, you can directly return an `IO` action from a parser, and
+execute it using `join` from `Control.Monad`.
+
+```haskell
+start :: String -> IO ()
+stop :: IO ()
+
+opts :: Parser (IO ())
+opts = subparser
+  ( command "start" (info (start <$> argument str idm) idm)
+  & command "stop"  (info (pure stop) idm) )
+
+main :: IO ()
+main = join $ execParser (info opts idm)
+```
+
 # Option builders
 
 Builders allow you to define parsers using a convenient combinator-based
@@ -254,12 +270,12 @@
 scratch and finally lift it to a single-option parser, which can then be
 combined with other parsers using normal `Applicative` combinators.
 
-Modifiers are instances of the `Category` typeclass, so they can be combined
-using the composition operator `(.)` from `Control.Category`, but the
-`Options.Applicative.Builders` module provides a convenience operator `(&)`,
-which is just a specialized version of flipped composition, so that you don't
-need to import the `Category` module and hide the `(.)` operator from the
-`Prelude`.
+Modifiers are instances of the `Monoid` typeclass, so they can be combined
+using the composition function `mappend`, for which the
+`Options.Applicative.Builders` module provides a convenience alias `(&)`.
+
+Feel free to use `mappend` or `(<>)`, if you prefer. `(&)` is mostly there for
+backwards compatibility with the previous implementation.
 
 See the haddock documentation for `Options.Applicative.Builder` for a full list
 of builders and modifiers.
diff --git a/optparse-applicative.cabal b/optparse-applicative.cabal
--- a/optparse-applicative.cabal
+++ b/optparse-applicative.cabal
@@ -1,5 +1,5 @@
 name:                optparse-applicative
-version:             0.2.0
+version:             0.3.0
 synopsis:            Utilities and combinators for parsing command line options
 description:
     Here is a simple example of an applicative option parser:
@@ -54,7 +54,7 @@
  >Usage: hello --hello TARGET [--quiet]
  >  Print a greeting for TARGET
  >
- >Common options:
+ >Available options:
  >  -h,--help                Show this help text
  >  --hello TARGET           Target for the greeting
  >  --quiet                  Whether to be quiet
@@ -81,8 +81,6 @@
                        Options.Applicative.Extra,
                        Options.Applicative.Help
   build-depends:       base == 4.*,
-                       data-lens == 2.10.*,
-                       data-default == 0.4.*,
                        transformers >= 0.2 && < 0.4
 test-suite tests
   type:                exitcode-stdio-1.0
@@ -90,7 +88,7 @@
   main-is:             Tests.hs
   build-depends:       base == 4.*,
                        HUnit == 1.2.*,
-                       optparse-applicative == 0.2.*,
+                       optparse-applicative == 0.3.*,
                        test-framework == 0.6.*,
                        test-framework-hunit == 0.2.*,
                        test-framework-th-prime == 0.0.*
