diff --git a/Options/Applicative/Common.hs b/Options/Applicative/Common.hs
--- a/Options/Applicative/Common.hs
+++ b/Options/Applicative/Common.hs
@@ -42,6 +42,7 @@
   runP,
   setContext,
   mapParser,
+  treeMapParser,
   optionNames
   ) where
 
@@ -136,10 +137,8 @@
   , do (p2', args') <- stepParser p2 arg args
        return (p1 <*> p2', args') ]
 stepParser (AltP p1 p2) arg args = msum
-  [ do (p1', args') <- stepParser p1 arg args
-       return (p1' <|> p2, args')
-  , do (p2', args') <- stepParser p2 arg args
-       return (p1 <|> p2', args') ]
+  [ stepParser p1 arg args
+  , stepParser p2 arg args ]
 stepParser (BindP p k) arg args = do
   (p', args') <- stepParser p arg args
   x <- evalParser p'
@@ -176,11 +175,20 @@
 evalParser (BindP p k) = evalParser p >>= evalParser . k
 
 -- | Map a polymorphic function over all the options of a parser, and collect
--- the results.
-mapParser :: (forall x . OptHelpInfo -> Option x -> b)
+-- the results in a list.
+mapParser :: (forall x. OptHelpInfo -> Option x -> b)
+              -> Parser a -> [b]
+mapParser f = flatten . treeMapParser f
+  where
+    flatten (Leaf x) = [x]
+    flatten (MultNode xs) = xs >>= flatten
+    flatten (AltNode xs) = xs >>= flatten
+
+-- | Like 'mapParser', but collect the results in a tree structure.
+treeMapParser :: (forall x . OptHelpInfo -> Option x -> b)
           -> Parser a
-          -> [b]
-mapParser = go False False
+          -> OptTree b
+treeMapParser g = simplify . go False False g
   where
     has_default :: Parser a -> Bool
     has_default p = case runP (evalParser p) of
@@ -189,10 +197,30 @@
 
     go :: Bool -> Bool
        -> (forall x . OptHelpInfo -> Option x -> b)
-       -> Parser a -> [b]
-    go _ _ _ (NilP _) = []
-    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
+       -> Parser a
+       -> OptTree b
+    go _ _ _ (NilP _) = MultNode []
+    go m d f (OptP opt) = Leaf (f (OptHelpInfo m d) opt)
+    go m d f (MultP p1 p2) = MultNode [go m d f p1, go m d f p2]
+    go m d f (AltP p1 p2) = AltNode [go m d' f p1, go m d' f p2]
       where d' = d || has_default p1 || has_default p2
     go _ d f (BindP p _) = go True d f p
+
+simplify :: OptTree a -> OptTree a
+simplify (Leaf x) = Leaf x
+simplify (MultNode xs) =
+  case concatMap (remove_mult . simplify) xs of
+    [x] -> x
+    xs' -> MultNode xs'
+  where
+    remove_mult (MultNode ts) = ts
+    remove_mult t = [t]
+simplify (AltNode xs) =
+  case concatMap (remove_alt . simplify) xs of
+    []  -> MultNode []
+    [x] -> x
+    xs' -> AltNode xs'
+  where
+    remove_alt (AltNode ts) = ts
+    remove_alt (MultNode []) = []
+    remove_alt t = [t]
diff --git a/Options/Applicative/Help.hs b/Options/Applicative/Help.hs
--- a/Options/Applicative/Help.hs
+++ b/Options/Applicative/Help.hs
@@ -66,12 +66,18 @@
 
 -- | Generate a brief help text for a parser.
 briefDesc :: ParserPrefs -> Parser a -> String
-briefDesc pprefs = foldr (<+>) "" . mapParser (optDesc pprefs style)
+briefDesc pprefs = fold_tree . treeMapParser (optDesc pprefs style)
   where
     style = OptDescStyle
       { descSep = "|"
       , descHidden = False
       , descSurround = True }
+
+    fold_tree (Leaf x) = x
+    fold_tree (MultNode xs) = unwords (fold_trees xs)
+    fold_tree (AltNode xs) = "(" ++ intercalate " | " (fold_trees xs) ++ ")"
+
+    fold_trees = filter (not . null) . map fold_tree
 
 -- | Generate a full help text for a parser.
 fullDesc :: ParserPrefs -> Parser a -> [String]
diff --git a/Options/Applicative/Types.hs b/Options/Applicative/Types.hs
--- a/Options/Applicative/Types.hs
+++ b/Options/Applicative/Types.hs
@@ -13,6 +13,7 @@
   Parser(..),
   ParserFailure(..),
   OptHelpInfo(..),
+  OptTree(..),
 
   optVisibility,
   optMetaVar,
@@ -128,6 +129,12 @@
 data OptHelpInfo = OptHelpInfo
   { hinfoMulti :: Bool
   , hinfoDefault :: Bool }
+
+data OptTree a
+  = Leaf a
+  | MultNode [OptTree a]
+  | AltNode [OptTree a]
+  deriving (Functor, Show)
 
 optVisibility :: Option a -> OptVisibility
 optVisibility = propVisibility . optProps
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.3.1
+version:             0.3.2
 synopsis:            Utilities and combinators for parsing command line options
 description:
     Here is a simple example of an applicative option parser:
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -98,5 +98,29 @@
         (err "test")
     Right r  -> assertFailure $ "unexpected result: " ++ show r
 
+case_alt_cont :: Assertion
+case_alt_cont = do
+  let p = Alternatives.a <|> Alternatives.b
+      i = info p idm
+      result = run i ["-a", "-b"]
+  case result of
+    Left _ -> return ()
+    Right r -> assertFailure $ "unexpected result: " ++ show r
+
+case_alt_help :: Assertion
+case_alt_help = do
+  let p = p1 <|> p2 <|> p3
+      p1 = (Just . Left)
+        <$> strOption ( long "virtual-machine"
+                      & metavar "VM"
+                      & help "Virtual machine name" )
+      p2 = (Just . Right)
+        <$> strOption ( long "cloud-service"
+                      & metavar "CS"
+                      & help "Cloud service name" )
+      p3 = flag' Nothing ( long "dry-run" )
+      i = info (p <**> helper) idm
+  checkHelpText "alt" i ["--help"]
+
 main :: IO ()
 main = $(defaultMainGenerator)
