diff --git a/CHANGES.txt b/CHANGES.txt
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,9 @@
 Changelog for Safe
 
+0.3.18, released 2019-12-04
+    #27, deprecate maximumDef and friends, fold*1Def
+    #27, add maximumBounded and friends
+    Stop supporting GHC 7.4 to 7.8
 0.3.17, released 2018-03-09
     Improve the display of errors, less internal callstack
     Add a few missing Partial constraints
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright Neil Mitchell 2007-2018.
+Copyright Neil Mitchell 2007-2019.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Safe [![Hackage version](https://img.shields.io/hackage/v/safe.svg?label=Hackage)](https://hackage.haskell.org/package/safe) [![Build Status](https://img.shields.io/travis/ndmitchell/safe.svg)](https://travis-ci.org/ndmitchell/safe)
+# Safe [![Hackage version](https://img.shields.io/hackage/v/safe.svg?label=Hackage)](https://hackage.haskell.org/package/safe) [![Stackage version](https://www.stackage.org/package/safe/badge/nightly?label=Stackage)](https://www.stackage.org/package/safe) [![Build status](https://img.shields.io/travis/ndmitchell/safe/master.svg?label=Build)](https://travis-ci.org/ndmitchell/safe)
 
 A library wrapping `Prelude`/`Data.List` functions that can throw exceptions, such as `head` and `!!`. Each unsafe function has up to four variants, e.g. with `tail`:
 
diff --git a/Safe.hs b/Safe.hs
--- a/Safe.hs
+++ b/Safe.hs
@@ -28,10 +28,13 @@
     initMay, initDef, initNote, initSafe,
     headMay, headDef, headNote,
     lastMay, lastDef, lastNote,
-    minimumMay, minimumDef, minimumNote,
-    maximumMay, maximumDef, maximumNote,
-    minimumByMay, minimumByDef, minimumByNote,
-    maximumByMay, maximumByDef, maximumByNote,
+    minimumMay, minimumNote,
+    maximumMay, maximumNote,
+    minimumByMay, minimumByNote,
+    maximumByMay, maximumByNote,
+    minimumBoundBy, maximumBoundBy,
+    maximumBounded, maximumBound,
+    minimumBounded, minimumBound,
     foldr1May, foldr1Def, foldr1Note,
     foldl1May, foldl1Def, foldl1Note,
     foldl1May', foldl1Def', foldl1Note',
@@ -50,6 +53,8 @@
     succMay, succDef, succNote, succSafe,
     predMay, predDef, predNote, predSafe,
     indexMay, indexDef, indexNote,
+    -- * Deprecated
+    minimumDef, maximumDef, minimumByDef, maximumByDef
     ) where
 
 import Safe.Util
@@ -144,10 +149,6 @@
 minimumMay = liftMay null minimum
 maximumMay = liftMay null maximum
 
-minimumDef, maximumDef :: Ord a => a -> [a] -> a
-minimumDef def = fromMaybe def . minimumMay
-maximumDef def = fromMaybe def . maximumMay
-
 minimumNote, maximumNote :: (Partial, Ord a) => String -> [a] -> a
 minimumNote note x = withFrozenCallStack $ fromNote note "minumumNote []" $ minimumMay x
 maximumNote note x = withFrozenCallStack $ fromNote note "maximumNote []" $ maximumMay x
@@ -156,25 +157,45 @@
 minimumByMay = liftMay null . minimumBy
 maximumByMay = liftMay null . maximumBy
 
-minimumByDef, maximumByDef :: a -> (a -> a -> Ordering) -> [a] -> a
-minimumByDef def = fromMaybe def .^ minimumByMay
-maximumByDef def = fromMaybe def .^ maximumByMay
-
 minimumByNote, maximumByNote :: Partial => String -> (a -> a -> Ordering) -> [a] -> a
 minimumByNote note f x = withFrozenCallStack $ fromNote note "minumumByNote []" $ minimumByMay f x
 maximumByNote note f x = withFrozenCallStack $ fromNote note "maximumByNote []" $ maximumByMay f x
 
+-- | The largest element of a list with respect to the
+-- given comparison function. The result is bounded by the value given as the first argument.
+maximumBoundBy :: a -> (a -> a -> Ordering) -> [a] -> a
+maximumBoundBy x f xs = maximumBy f $ x : xs
 
+-- | The smallest element of a list with respect to the
+-- given comparison function. The result is bounded by the value given as the first argument.
+minimumBoundBy :: a -> (a -> a -> Ordering) -> [a] -> a
+minimumBoundBy x f xs = minimumBy f $ x : xs
+
+-- | The largest element of a list.
+-- The result is bounded by the value given as the first argument.
+maximumBound :: Ord a => a -> [a] -> a
+maximumBound x xs = maximum $ x : xs
+
+-- | The smallest element of a list.
+-- The result is bounded by the value given as the first argument.
+minimumBound :: Ord a => a -> [a] -> a
+minimumBound x xs = minimum $ x : xs
+
+-- | The largest element of a list.
+-- The result is bounded by 'minBound'.
+maximumBounded :: (Ord a, Bounded a) => [a] -> a
+maximumBounded = maximumBound minBound
+
+-- | The largest element of a list.
+-- The result is bounded by 'maxBound'.
+minimumBounded :: (Ord a, Bounded a) => [a] -> a
+minimumBounded = minimumBound maxBound
+
 foldr1May, foldl1May, foldl1May' :: (a -> a -> a) -> [a] -> Maybe a
 foldr1May = liftMay null . foldr1
 foldl1May = liftMay null . foldl1
 foldl1May' = liftMay null . foldl1'
 
-foldr1Def, foldl1Def, foldl1Def' :: a -> (a -> a -> a) -> [a] -> a
-foldr1Def def = fromMaybe def .^ foldr1May
-foldl1Def def = fromMaybe def .^ foldl1May
-foldl1Def' def = fromMaybe def .^ foldl1May'
-
 foldr1Note, foldl1Note, foldl1Note' :: Partial => String -> (a -> a -> a) -> [a] -> a
 foldr1Note note f x = withFrozenCallStack $ fromNote note "foldr1Note []" $ foldr1May f x
 foldl1Note note f x = withFrozenCallStack $ fromNote note "foldl1Note []" $ foldl1May f x
@@ -344,3 +365,26 @@
 
 indexNote :: (Partial, Ix a) => String -> (a, a) -> a -> Int
 indexNote note x y = withFrozenCallStack $ fromNote note "indexNote, out of range" $ indexMay x y
+
+---------------------------------------------------------------------
+-- DEPRECATED
+
+{-# DEPRECATED minimumDef "Use @minimumBound@ instead." #-}
+{-# DEPRECATED maximumDef "Use @maximumBound@ instead." #-}
+minimumDef, maximumDef :: Ord a => a -> [a] -> a
+minimumDef def = fromMaybe def . minimumMay
+maximumDef def = fromMaybe def . maximumMay
+
+{-# DEPRECATED minimumByDef "Use @minimumBoundBy@ instead." #-}
+{-# DEPRECATED maximumByDef "Use @maximumBoundBy@ instead." #-}
+minimumByDef, maximumByDef :: a -> (a -> a -> Ordering) -> [a] -> a
+minimumByDef def = fromMaybe def .^ minimumByMay
+maximumByDef def = fromMaybe def .^ maximumByMay
+
+{-# DEPRECATED foldr1Def "Use @foldr1May@ instead." #-}
+{-# DEPRECATED foldl1Def "Use @foldl1May@ instead." #-}
+{-# DEPRECATED foldl1Def' "Use @foldl1May'@ instead." #-}
+foldr1Def, foldl1Def, foldl1Def' :: a -> (a -> a -> a) -> [a] -> a
+foldr1Def def = fromMaybe def .^ foldr1May
+foldl1Def def = fromMaybe def .^ foldl1May
+foldl1Def' def = fromMaybe def .^ foldl1May'
diff --git a/Safe/Exact.hs b/Safe/Exact.hs
--- a/Safe/Exact.hs
+++ b/Safe/Exact.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE ConstraintKinds  #-}
+{-# LANGUAGE TupleSections    #-}
 {- |
 Provides functions that raise errors in corner cases instead of returning \"best effort\"
 results, then provides wrappers like the "Safe" module. For example:
@@ -103,7 +104,7 @@
 -- >   | otherwise                = error "some message"
 splitAtExact :: Partial => Int -> [a] -> ([a], [a])
 splitAtExact i xs = withFrozenCallStack $ splitAtExact_ (addNote "" "splitAtExact")
-    (\x -> ([], x)) (\a b -> first (a:) b) i xs
+    ([],) (\a b -> first (a:) b) i xs
 
 takeExactNote :: Partial => String -> Int -> [a] -> [a]
 takeExactNote note i xs = withFrozenCallStack $ splitAtExact_ (addNote note "takeExactNote") (const []) (:) i xs
@@ -125,7 +126,7 @@
 
 splitAtExactNote :: Partial => String -> Int -> [a] -> ([a], [a])
 splitAtExactNote note i xs = withFrozenCallStack $ splitAtExact_ (addNote note "splitAtExactNote")
-    (\x -> ([], x)) (\a b -> first (a:) b) i xs
+    ([],) (\a b -> first (a:) b) i xs
 
 splitAtExactMay :: Int -> [a] -> Maybe ([a], [a])
 splitAtExactMay = splitAtExact_ (const Nothing)
diff --git a/Safe/Foldable.hs b/Safe/Foldable.hs
--- a/Safe/Foldable.hs
+++ b/Safe/Foldable.hs
@@ -1,5 +1,4 @@
 {-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE CPP              #-}
 {-# LANGUAGE ConstraintKinds  #-}
 {- |
 'Foldable' functions, with wrappers like the "Safe" module.
@@ -11,12 +10,16 @@
     foldl1May, foldl1Def, foldl1Note,
     foldr1May, foldr1Def, foldr1Note,
     findJustDef, findJustNote,
-    minimumMay, minimumDef, minimumNote,
-    maximumMay, maximumDef, maximumNote,
-    minimumByMay, minimumByDef, minimumByNote,
-    maximumByMay, maximumByDef, maximumByNote,
+    minimumMay, minimumNote,
+    maximumMay, maximumNote,
+    minimumByMay, minimumByNote,
+    maximumByMay, maximumByNote,
+    maximumBoundBy, minimumBoundBy,
+    maximumBounded, maximumBound,
+    minimumBounded, minimumBound,
     -- * Deprecated
-    foldl1Safe, foldr1Safe, findJustSafe
+    foldl1Safe, foldr1Safe, findJustSafe,
+    minimumDef, maximumDef, minimumByDef, maximumByDef
     ) where
 
 import Safe.Util
@@ -33,52 +36,64 @@
 fromNote :: Partial => String -> String -> Maybe a -> a
 fromNote = fromNoteModule "Safe.Foldable"
 
-isNull :: Foldable t => t a -> Bool
-#if __GLASGOW_HASKELL__ < 710
-isNull = null . toList
-#else
-isNull = F.null
-#endif
 
 ---------------------------------------------------------------------
 -- WRAPPERS
 
 foldl1May, foldr1May :: Foldable t => (a -> a -> a) -> t a -> Maybe a
-foldl1May = liftMay isNull . F.foldl1
-foldr1May = liftMay isNull . F.foldr1
+foldl1May = liftMay F.null . F.foldl1
+foldr1May = liftMay F.null . F.foldr1
 
 foldl1Note, foldr1Note :: (Partial, Foldable t) => String -> (a -> a -> a) -> t a -> a
 foldl1Note note f x = withFrozenCallStack $ fromNote note "foldl1Note on empty" $ foldl1May f x
 foldr1Note note f x = withFrozenCallStack $ fromNote note "foldr1Note on empty" $ foldr1May f x
 
-foldl1Def, foldr1Def :: Foldable t => a -> (a -> a -> a) -> t a -> a
-foldl1Def def = fromMaybe def .^ foldl1May
-foldr1Def def = fromMaybe def .^ foldr1May
-
 minimumMay, maximumMay :: (Foldable t, Ord a) => t a -> Maybe a
-minimumMay = liftMay isNull F.minimum
-maximumMay = liftMay isNull F.maximum
-
-minimumDef, maximumDef :: (Foldable t, Ord a) => a -> t a -> a
-minimumDef def = fromMaybe def . minimumMay
-maximumDef def = fromMaybe def . maximumMay
+minimumMay = liftMay F.null F.minimum
+maximumMay = liftMay F.null F.maximum
 
 minimumNote, maximumNote :: (Partial, Foldable t, Ord a) => String -> t a -> a
 minimumNote note x = withFrozenCallStack $ fromNote note "minimumNote on empty" $ minimumMay x
 maximumNote note x = withFrozenCallStack $ fromNote note "maximumNote on empty" $ maximumMay x
 
 minimumByMay, maximumByMay :: Foldable t => (a -> a -> Ordering) -> t a -> Maybe a
-minimumByMay = liftMay isNull . F.minimumBy
-maximumByMay = liftMay isNull . F.maximumBy
-
-minimumByDef, maximumByDef :: Foldable t => a -> (a -> a -> Ordering) -> t a -> a
-minimumByDef def = fromMaybe def .^ minimumByMay
-maximumByDef def = fromMaybe def .^ maximumByMay
+minimumByMay = liftMay F.null . F.minimumBy
+maximumByMay = liftMay F.null . F.maximumBy
 
 minimumByNote, maximumByNote :: (Partial, Foldable t) => String -> (a -> a -> Ordering) -> t a -> a
 minimumByNote note f x = withFrozenCallStack $ fromNote note "minimumByNote on empty" $ minimumByMay f x
 maximumByNote note f x = withFrozenCallStack $ fromNote note "maximumByNote on empty" $ maximumByMay f x
 
+-- | The largest element of a foldable structure with respect to the
+-- given comparison function. The result is bounded by the value given as the first argument.
+maximumBoundBy :: Foldable f => a -> (a -> a -> Ordering) -> f a -> a
+maximumBoundBy x f xs = maximumBy f $ x : toList xs
+
+-- | The smallest element of a foldable structure with respect to the
+-- given comparison function. The result is bounded by the value given as the first argument.
+minimumBoundBy :: Foldable f => a -> (a -> a -> Ordering) -> f a -> a
+minimumBoundBy x f xs = minimumBy f $ x : toList xs
+
+-- | The largest element of a foldable structure.
+-- The result is bounded by the value given as the first argument.
+maximumBound :: (Foldable f, Ord a) => a -> f a -> a
+maximumBound x xs = maximum $ x : toList xs
+
+-- | The smallest element of a foldable structure.
+-- The result is bounded by the value given as the first argument.
+minimumBound :: (Foldable f, Ord a) => a -> f a -> a
+minimumBound x xs = minimum $ x : toList xs
+
+-- | The largest element of a foldable structure.
+-- The result is bounded by 'minBound'.
+maximumBounded :: (Foldable f, Ord a, Bounded a) => f a -> a
+maximumBounded = maximumBound minBound
+
+-- | The largest element of a foldable structure.
+-- The result is bounded by 'maxBound'.
+minimumBounded :: (Foldable f, Ord a, Bounded a) => f a -> a
+minimumBounded = minimumBound maxBound
+
 -- |
 -- > findJust op = fromJust . find op
 findJust :: (Partial, Foldable t) => (a -> Bool) -> t a -> a
@@ -102,7 +117,24 @@
 foldr1Safe :: (Monoid m, Foldable t) => (m -> m -> m) -> t m -> m
 foldr1Safe fun = F.foldr fun mempty
 
-
 {-# DEPRECATED findJustSafe "Use @findJustDef mempty@ instead." #-}
 findJustSafe :: (Monoid m, Foldable t) => (m -> Bool) -> t m -> m
 findJustSafe = findJustDef mempty
+
+{-# DEPRECATED minimumDef "Use @minimumBound@ instead." #-}
+{-# DEPRECATED maximumDef "Use @maximumBound@ instead." #-}
+minimumDef, maximumDef :: (Foldable t, Ord a) => a -> t a -> a
+minimumDef def = fromMaybe def . minimumMay
+maximumDef def = fromMaybe def . maximumMay
+
+{-# DEPRECATED minimumByDef "Use @minimumBoundBy@ instead." #-}
+{-# DEPRECATED maximumByDef "Use @maximumBoundBy@ instead." #-}
+minimumByDef, maximumByDef :: Foldable t => a -> (a -> a -> Ordering) -> t a -> a
+minimumByDef def = fromMaybe def .^ minimumByMay
+maximumByDef def = fromMaybe def .^ maximumByMay
+
+{-# DEPRECATED foldr1Def "Use @foldr1May@ instead." #-}
+{-# DEPRECATED foldl1Def "Use @foldl1May@ instead." #-}
+foldl1Def, foldr1Def :: Foldable t => a -> (a -> a -> a) -> t a -> a
+foldl1Def def = fromMaybe def .^ foldl1May
+foldr1Def def = fromMaybe def .^ foldr1May
diff --git a/safe.cabal b/safe.cabal
--- a/safe.cabal
+++ b/safe.cabal
@@ -1,17 +1,17 @@
 cabal-version:  >= 1.18
 build-type:     Simple
 name:           safe
-version:        0.3.17
+version:        0.3.18
 license:        BSD3
 license-file:   LICENSE
 category:       Unclassified
 author:         Neil Mitchell <ndmitchell@gmail.com>
 maintainer:     Neil Mitchell <ndmitchell@gmail.com>
-copyright:      Neil Mitchell 2007-2018
+copyright:      Neil Mitchell 2007-2019
 homepage:       https://github.com/ndmitchell/safe#readme
 synopsis:       Library of safe (exception free) functions
 bug-reports:    https://github.com/ndmitchell/safe/issues
-tested-with:    GHC==8.2.2, GHC==8.0.2, GHC==7.10.3, GHC==7.8.4, GHC==7.6.3, GHC==7.4.2
+tested-with:    GHC==8.8.1, GHC==8.6.5, GHC==8.4.4, GHC==8.2.2, GHC==8.0.2, GHC==7.10.3
 description:
     A library wrapping @Prelude@/@Data.List@ functions that can throw exceptions, such as @head@ and @!!@.
     Each unsafe function has up to four variants, e.g. with @tail@:
