diff --git a/CHANGES.txt b/CHANGES.txt
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,14 @@
 Changelog for HLint (* = breaking change)
 
+2.2.11, released 2020-02-09
+    #868, fix some brackets in refactoring suggestions
+    #865, suggest biList if generalise-for-conciseness is turned on
+    #859, suggest regular if instead of a simple multi-way if
+    #860, improve the sortBy/sortOn hints
+    #862, only suggest TupleSections for 2-tuples once
+    #854, add more generalise-for-conciseness hints for Either/Maybe
+    #852, change maybe to fromMaybe, when the function is duplicated
+    #851, add a rule for maybe Nothing Just
 2.2.10, released 2020-02-02
     #846, add splitAt warnings
     #774, don't warn about 'Redundant compare' in == and /=
diff --git a/data/hlint.yaml b/data/hlint.yaml
--- a/data/hlint.yaml
+++ b/data/hlint.yaml
@@ -99,8 +99,8 @@
     - warn: {lhs: head (sortBy f x), rhs: minimumBy f x, side: isCompare f}
     - warn: {lhs: last (sortBy f x), rhs: maximumBy f x, side: isCompare f}
     - warn: {lhs: reverse (sortBy f x), rhs: sortBy (flip f) x, name: Avoid reverse, side: isCompare f, note: Stabilizes sort order}
-    - warn: {lhs: sortBy (comparing (flip f)), rhs: sortOn (Down . f)}
-    - warn: {lhs: sortBy (comparing f), rhs: sortOn f}
+    - warn: {lhs: sortBy (flip (comparing f)), rhs: sortOn (Down . f)}
+    - warn: {lhs: sortBy (comparing f), rhs: sortOn f, side: notEq f fst && notEq f snd}
     - warn: {lhs: reverse (sortOn f x), rhs: sortOn (Data.Ord.Down . f) x, name: Avoid reverse, note: Stabilizes sort order}
     - warn: {lhs: reverse (sort x), rhs: sortOn Data.Ord.Down x, name: Avoid reverse, note: Stabilizes sort order}
     - hint: {lhs: flip (g `on` h), rhs: flip g `on` h, name: Move flip}
@@ -303,8 +303,6 @@
     - warn: {lhs: x . id, rhs: x, name: Redundant id}
     - warn: {lhs: "((,) x)", rhs: "(_noParen_ x,)", name: Use tuple-section, note: RequiresExtension TupleSections}
     - warn: {lhs: "flip (,) x", rhs: "(,_noParen_ x)", name: Use tuple-section, note: RequiresExtension TupleSections}
-    - warn: {lhs: "\\y -> (x,y)", rhs: "(x,)", name: Use tuple-section, note: RequiresExtension TupleSections}
-    - warn: {lhs: "\\y -> (y,x)", rhs: "(,x)", name: Use tuple-section, note: RequiresExtension TupleSections}
 
     # CHAR
 
@@ -332,6 +330,7 @@
     - warn: {lhs: if a then (if b then t else f) else f, rhs: if a && b then t else f, name: Redundant if}
     - warn: {lhs: if x then True else y, rhs: x || y, side: notEq y False, name: Redundant if}
     - warn: {lhs: if x then y else False, rhs: x && y, side: notEq y True, name: Redundant if}
+    - warn: {lhs: if | b -> t | otherwise -> f, rhs: if b then t else f, name: Redundant multi-way if}
     - hint: {lhs: "case a of {True -> t; False -> f}", rhs: if a then t else f, name: Use if}
     - hint: {lhs: "case a of {False -> f; True -> t}", rhs: if a then t else f, name: Use if}
     - hint: {lhs: "case a of {True -> t; _ -> f}", rhs: if a then t else f, name: Use if}
@@ -516,6 +515,7 @@
     # MAYBE
 
     - warn: {lhs: maybe x id, rhs: Data.Maybe.fromMaybe x}
+    - warn: {lhs: maybe Nothing Just, rhs: id, name: Redundant maybe}
     - warn: {lhs: maybe False (const True), rhs: Data.Maybe.isJust}
     - warn: {lhs: maybe True (const False), rhs: Data.Maybe.isNothing}
     - warn: {lhs: maybe False (== x), rhs: (== Just x)}
@@ -552,6 +552,7 @@
     - hint: {lhs: maybe Nothing id, rhs: join}
     - hint: {lhs: maybe Nothing f x, rhs: f =<< x}
     - hint: {lhs: maybe (f x) (f . g), rhs: f . maybe x g, note: IncreasesLaziness, name: Too strict maybe}
+    - hint: {lhs: maybe (f x) f y, rhs: f (Data.Maybe.fromMaybe x y), note: IncreasesLaziness, name: Too strict maybe}
     - warn: {lhs: maybe x f (fmap g y), rhs: maybe x (f . g) y, name: Redundant fmap}
     - warn: {lhs: isJust (fmap f x), rhs: isJust x}
     - warn: {lhs: isNothing (fmap f x), rhs: isNothing x}
@@ -812,13 +813,23 @@
     - warn: {lhs: Data.Maybe.fromMaybe mempty, rhs: Data.Foldable.fold}
     - warn: {lhs: Data.Maybe.fromMaybe False, rhs: or}
     - warn: {lhs: Data.Maybe.fromMaybe True, rhs: and}
+    - warn: {lhs: Data.Maybe.fromMaybe 0, rhs: sum}
+    - warn: {lhs: Data.Maybe.fromMaybe 1, rhs: product}
+    - warn: {lhs: Data.Maybe.fromMaybe empty, rhs: Data.Foldable.asum}
+    - warn: {lhs: Data.Maybe.fromMaybe mzero, rhs: Data.Foldable.msum}
     - warn: {lhs: Data.Either.fromRight mempty, rhs: Data.Foldable.fold}
     - warn: {lhs: Data.Either.fromRight False, rhs: or}
     - warn: {lhs: Data.Either.fromRight True, rhs: and}
+    - warn: {lhs: Data.Either.fromRight 0, rhs: sum}
+    - warn: {lhs: Data.Either.fromRight 1, rhs: product}
+    - warn: {lhs: Data.Either.fromRight empty, rhs: Data.Foldable.asum}
+    - warn: {lhs: Data.Either.fromRight mzero, rhs: Data.Foldable.msum}
     - warn: {lhs: if f x then Just x else Nothing, rhs: mfilter f (Just x)}
     - hint: {lhs: maybe (pure ()), rhs: traverse_, note: IncreasesLaziness}
     - hint: {lhs: fromMaybe (pure ()), rhs: sequenceA_, note: IncreasesLaziness}
     - hint: {lhs: fromRight (pure ()), rhs: sequenceA_, note: IncreasesLaziness}
+    - hint: {lhs: "[fst x, snd x]", rhs: Data.Bifoldable.biList x}
+    - hint: {lhs: "\\(x, y) -> [x, y]", rhs: Data.Bifoldable.biList, note: IncreasesLaziness}
 
 - group:
     name: dollar
@@ -1029,7 +1040,7 @@
 # main = hello .~ Just 12 -- hello ?~ 12
 # foo = liftIO $ window `on` deleteEvent $ do a; b
 # no = sort <$> f input `shouldBe` sort <$> x
-# sortBy (comparing snd) -- sortOn snd
+# sortBy (comparing length) -- sortOn length
 # myJoin = on $ child ^. ChildParentId ==. parent ^. ParentId
 # foo = typeOf (undefined :: Foo Int) -- typeRep (Proxy :: Proxy (Foo Int))
 # foo = typeOf (undefined :: a) -- typeRep (Proxy :: Proxy a)
diff --git a/hlint.cabal b/hlint.cabal
--- a/hlint.cabal
+++ b/hlint.cabal
@@ -1,7 +1,7 @@
 cabal-version:      >= 1.18
 build-type:         Simple
 name:               hlint
-version:            2.2.10
+version:            2.2.11
 license:            BSD3
 license-file:       LICENSE
 category:           Development
@@ -68,11 +68,12 @@
         refact >= 0.3,
         aeson >= 1.1.2.0,
         filepattern >= 0.1.1,
-        ghc-lib-parser-ex == 8.8.4.*
+        ghc-lib-parser-ex == 8.8.5.*
     if !flag(ghc-lib) && impl(ghc >= 8.8.0) && impl(ghc < 8.9.0)
         build-depends:
           ghc == 8.8.*,
-          ghc-boot-th
+          ghc-boot-th,
+          ghc-boot
     else
         build-depends:
           ghc-lib-parser == 8.8.*
diff --git a/src/GHC/Util/FreeVars.hs b/src/GHC/Util/FreeVars.hs
--- a/src/GHC/Util/FreeVars.hs
+++ b/src/GHC/Util/FreeVars.hs
@@ -30,7 +30,7 @@
 ( ^- ) :: Set OccName -> Set OccName -> Set OccName
 ( ^- ) = Set.difference
 
--- See [Note : Spack leaks lurking here?] below.
+-- See [Note : Space leaks lurking here?] below.
 data Vars' = Vars'{bound' :: Set OccName, free' :: Set OccName}
 
 -- Useful for debugging.
diff --git a/src/GHC/Util/HsExpr.hs b/src/GHC/Util/HsExpr.hs
--- a/src/GHC/Util/HsExpr.hs
+++ b/src/GHC/Util/HsExpr.hs
@@ -35,6 +35,7 @@
 import Data.Data
 import Data.Generics.Uniplate.Data
 import Data.List.Extra
+import Data.Tuple.Extra
 
 import Refact.Types hiding (Match)
 import qualified Refact.Types as R (SrcSpan)
@@ -211,30 +212,40 @@
 replaceBranches' x = ([], \[] -> x)
 
 
--- Like needBracket, but with a special case for 'a . b . b', which was
+-- Like needBracket', but with a special case for 'a . b . b', which was
 -- removed from haskell-src-exts-util-0.2.2.
 needBracketOld' :: Int -> LHsExpr GhcPs -> LHsExpr GhcPs -> Bool
 needBracketOld' i parent child
   | isDotApp parent, isDotApp child, i == 2 = False
   | otherwise = needBracket' i parent child
 
-transformBracketOld' :: (LHsExpr GhcPs -> Maybe (LHsExpr GhcPs)) -> LHsExpr GhcPs -> LHsExpr GhcPs
-transformBracketOld' op = snd . g
+transformBracketOld' :: (LHsExpr GhcPs -> Maybe (LHsExpr GhcPs)) -> LHsExpr GhcPs -> (LHsExpr GhcPs, LHsExpr GhcPs)
+transformBracketOld' op = first snd . g
   where
-    g = f . descendBracketOld' g
+    g = first f . descendBracketOld' g
     f x = maybe (False, x) (True, ) (op x)
 
 -- Descend, and if something changes then add/remove brackets
--- appropriately
-descendBracketOld' :: (LHsExpr GhcPs -> (Bool, LHsExpr GhcPs)) -> LHsExpr GhcPs -> LHsExpr GhcPs
-descendBracketOld' op x = descendIndex' g x
+-- appropriately. Returns (suggested replacement, refactor template).
+-- Whenever a bracket is added to the suggested replacement, a
+-- corresponding bracket is added to the refactor template.
+descendBracketOld' :: (LHsExpr GhcPs -> ((Bool, LHsExpr GhcPs), LHsExpr GhcPs))
+                   -> LHsExpr GhcPs
+                   -> (LHsExpr GhcPs, LHsExpr GhcPs)
+descendBracketOld' op x = (descendIndex' g1 x, descendIndex' g2 x)
   where
-    g i y = if a then f i b else b
-      where (a, b) = op y
+    g i y = if a then (f1 i b z, f2 i b z) else (b, z)
+      where ((a, b), z) = op y
 
-    f i (LL _ (HsPar _ y)) | not $ needBracketOld' i x y = y
-    f i y                  | needBracketOld' i x y = addParen' y
-    f _ y                  = y
+    g1 = (fst .) . g
+    g2 = (snd .) . g
+
+    f i (LL _ (HsPar _ y)) z | not $ needBracketOld' i x y = (y, z)
+    f i y z                  | needBracketOld' i x y = (addParen' y, addParen' z)
+    f _ y z                  = (y, z)
+
+    f1 = ((fst .) .) . f
+    f2 = ((snd .) .) . f
 
 reduce' :: LHsExpr GhcPs -> LHsExpr GhcPs
 reduce' = fromParen' . transform reduce1'
diff --git a/src/GHC/Util/Unify.hs b/src/GHC/Util/Unify.hs
--- a/src/GHC/Util/Unify.hs
+++ b/src/GHC/Util/Unify.hs
@@ -58,7 +58,10 @@
           f _ = Nothing
 
 -- Peform a substition.
-substitute' :: Subst' (LHsExpr GhcPs) -> LHsExpr GhcPs -> LHsExpr GhcPs
+-- Returns (suggested replacement, refactor template), both with brackets added
+-- as needed.
+-- Example: (traverse foo (bar baz), traverse f (x))
+substitute' :: Subst' (LHsExpr GhcPs) -> LHsExpr GhcPs -> (LHsExpr GhcPs, LHsExpr GhcPs)
 substitute' (Subst' bind) = transformBracketOld' exp . transformBi pat . transformBi typ
   where
     exp :: LHsExpr GhcPs -> Maybe (LHsExpr GhcPs)
diff --git a/src/HSE/Util.hs b/src/HSE/Util.hs
--- a/src/HSE/Util.hs
+++ b/src/HSE/Util.hs
@@ -395,6 +395,7 @@
 
 -- | (a, bs) means extension a implies all of bs.
 --   Taken from https://downloads.haskell.org/~ghc/master/users-guide/glasgow_exts.html#language-options
+--   In the GHC source at DynFlags.impliedXFlags
 extensionImplications :: [(Extension, [Extension])]
 extensionImplications = map (first EnableExtension) $
     (RebindableSyntax, [DisableExtension ImplicitPrelude]) :
diff --git a/src/Hint/Import.hs b/src/Hint/Import.hs
--- a/src/Hint/Import.hs
+++ b/src/Hint/Import.hs
@@ -73,8 +73,9 @@
   concatMap preferHierarchicalImports ms
 
 reduceImports :: [LImportDecl GhcPs] -> [Idea]
-reduceImports ms =
-  [rawIdea' Hint.Type.Warning "Use fewer imports" (getLoc $ head ms) (f ms) (Just $ f x) [] rs
+reduceImports [] = []
+reduceImports ms@(m:_) =
+  [rawIdea' Hint.Type.Warning "Use fewer imports" (getLoc m) (f ms) (Just $ f x) [] rs
   | Just (x, rs) <- [simplify ms]]
   where f = unlines . map unsafePrettyPrint
 
diff --git a/src/Hint/Match.hs b/src/Hint/Match.hs
--- a/src/Hint/Match.hs
+++ b/src/Hint/Match.hs
@@ -111,8 +111,8 @@
     [ (idea' (hintRuleSeverity m) (hintRuleName m) x y [r]){ideaNote=notes}
     | (name, expr) <- findDecls' decl
     , (parent,x) <- universeParentExp' expr
-    , m <- matches, Just (y, notes, subst) <- [matchIdea' s name m parent x]
-    , let r = R.Replace R.Expr (toSS' x) subst (unsafePrettyPrint $ unextendInstances (hintRuleGhcRHS m))
+    , m <- matches, Just (y, tpl, notes, subst) <- [matchIdea' s name m parent x]
+    , let r = R.Replace R.Expr (toSS' x) subst (unsafePrettyPrint tpl)
     ]
 
 -- | A list of root expressions, with their associated names
@@ -127,7 +127,7 @@
            -> HintRule
            -> Maybe (Int, LHsExpr GhcPs)
            -> LHsExpr GhcPs
-           -> Maybe (LHsExpr GhcPs, [Note], [(String, R.SrcSpan)])
+           -> Maybe (LHsExpr GhcPs, LHsExpr GhcPs, [Note], [(String, R.SrcSpan)])
 matchIdea' sb declName HintRule{..} parent x = do
   let lhs = unextendInstances hintRuleGhcLHS
       rhs = unextendInstances hintRuleGhcRHS
@@ -138,8 +138,8 @@
 
   -- Need to check free vars before unqualification, but after subst
   -- (with 'e') need to unqualify before substitution (with 'res').
-  let e = substitute' u rhs
-      res = addBracketTy' (addBracket' parent $ performSpecial' $ substitute' u $ unqualify' sa sb rhs)
+  let (e, tpl) = substitute' u rhs
+      res = addBracketTy' (addBracket' parent $ performSpecial' $ fst $ substitute' u $ unqualify' sa sb rhs)
   guard $ (freeVars' e Set.\\ Set.filter (not . isUnifyVar . occNameString) (freeVars' rhs)) `Set.isSubsetOf` freeVars' x
       -- Check no unexpected new free variables.
 
@@ -152,7 +152,7 @@
   guard $ checkSide' (unextendInstances <$> hintRuleGhcSide) $ ("original", x) : ("result", res) : fromSubst' u
   guard $ checkDefine' declName parent res
 
-  return (res, hintRuleNotes, [(s, toSS' pos) | (s, pos) <- fromSubst' u, getLoc pos /= noSrcSpan])
+  return (res, tpl, hintRuleNotes, [(s, toSS' pos) | (s, pos) <- fromSubst' u, getLoc pos /= noSrcSpan])
 
 ---------------------------------------------------------------------
 -- SIDE CONDITIONS
diff --git a/src/Hint/Monad.hs b/src/Hint/Monad.hs
--- a/src/Hint/Monad.hs
+++ b/src/Hint/Monad.hs
@@ -133,8 +133,8 @@
            -> [ExprLStmt GhcPs] -> [Idea]
 
 -- Rewrite 'do return x; $2' as 'do $2'.
-monadStep wrap o@(LL _ (BodyStmt _ (fromRet -> Just (ret, _)) _ _ ) : x : xs)
-  = [warn' ("Redundant " ++ ret) (wrap o) (wrap $ x:xs) [Delete Stmt (toSS' (head o))]]
+monadStep wrap os@(o@(LL _ (BodyStmt _ (fromRet -> Just (ret, _)) _ _ )) : xs@(_:_))
+  = [warn' ("Redundant " ++ ret) (wrap os) (wrap xs) [Delete Stmt (toSS' o)]]
 
 -- Rewrite 'do a <- $1; return a' as 'do $1'.
 monadStep wrap o@[ g@(LL _ (BindStmt _ (LL _ (VarPat _ (L _ p))) x _ _ ))
diff --git a/src/Hint/Pragma.hs b/src/Hint/Pragma.hs
--- a/src/Hint/Pragma.hs
+++ b/src/Hint/Pragma.hs
@@ -32,6 +32,7 @@
 
 import Hint.Type(ModuHint,ModuleEx(..),Idea(..),Severity(..),toSS',rawIdea',prettyExtension,glasgowExts)
 import Data.List.Extra
+import qualified Data.List.NonEmpty as NE
 import Data.Maybe
 import Refact.Types
 import qualified Refact.Types as R
@@ -52,7 +53,7 @@
              -> [(Located AnnotationComment, [String])]
              -> [Idea]
 optToPragma flags langExts =
-  [pragmaIdea (OptionsToComment (map fst old) ys rs) | old /= []]
+  [pragmaIdea (OptionsToComment (fst <$> old2) ys rs) | Just old2 <- [NE.nonEmpty old]]
   where
       (old, new, ns, rs) =
         unzip4 [(old, new, ns, r)
@@ -73,7 +74,7 @@
 
 data PragmaIdea = SingleComment (Located AnnotationComment) (Located AnnotationComment)
                  | MultiComment (Located AnnotationComment) (Located AnnotationComment) (Located AnnotationComment)
-                 | OptionsToComment [Located AnnotationComment] [Located AnnotationComment] [Refactoring R.SrcSpan]
+                 | OptionsToComment (NE.NonEmpty (Located AnnotationComment)) [Located AnnotationComment] [Refactoring R.SrcSpan]
 
 pragmaIdea :: PragmaIdea -> Idea
 pragmaIdea pidea =
@@ -87,8 +88,8 @@
         [ ModifyComment (toSS' repl) (comment new)
         , ModifyComment (toSS' delete) ""]
     OptionsToComment old new r ->
-      mkLanguage (getLoc . head $ old)
-        (f old) (Just $ f new) []
+      mkLanguage (getLoc . NE.head $ old)
+        (f $ NE.toList old) (Just $ f new) []
         r
     where
           f = unlines . map comment
diff --git a/src/Report.hs b/src/Report.hs
--- a/src/Report.hs
+++ b/src/Report.hs
@@ -5,6 +5,7 @@
 import Idea
 import Data.Tuple.Extra
 import Data.List.Extra
+import qualified Data.List.NonEmpty as NE
 import Data.Maybe
 import Data.Version
 import HSE.All
@@ -26,7 +27,7 @@
 writeReport dataDir file ideas = timedIO "Report" file $ writeTemplate dataDir inner file
     where
         generateIds :: [String] -> [(String,Int)] -- sorted by name
-        generateIds = map (head &&& length) . group -- must be already sorted
+        generateIds = map (NE.head &&& length) . NE.group -- must be already sorted
         files = generateIds $ sort $ map (srcSpanFilename . ideaSpan) ideas
         hints = generateIds $ map hintName $ sortOn (negate . fromEnum . ideaSeverity &&& hintName) ideas
         hintName x = show (ideaSeverity x) ++ ": " ++ ideaHint x
