diff --git a/Criterion.hs b/Criterion.hs
--- a/Criterion.hs
+++ b/Criterion.hs
@@ -30,6 +30,8 @@
     , whnf
     , nfIO
     , whnfIO
+    , nfAppIO
+    , whnfAppIO
     -- * For interactive use
     , benchmark
     , benchmarkWith
diff --git a/Criterion/Main.hs b/Criterion/Main.hs
--- a/Criterion/Main.hs
+++ b/Criterion/Main.hs
@@ -48,6 +48,8 @@
     , whnf
     , nfIO
     , whnfIO
+    , nfAppIO
+    , whnfAppIO
     -- * Turning a suite of benchmarks into a program
     , defaultMain
     , defaultMainWith
@@ -186,7 +188,7 @@
 -- number of times.  We are most interested in benchmarking two
 -- things:
 --
--- * 'IO' actions.  Any 'IO' action can be benchmarked directly.
+-- * 'IO' actions.  Most 'IO' actions can be benchmarked directly.
 --
 -- * Pure functions.  GHC optimises aggressively when compiling with
 --   @-O@, so it is easy to write innocent-looking benchmark code that
@@ -196,12 +198,25 @@
 
 -- $io
 --
--- Any 'IO' action can be benchmarked easily if its type resembles
--- this:
+-- Most 'IO' actions can be benchmarked easily using one of the following
+-- two functions:
 --
 -- @
--- 'IO' a
+-- 'nfIO'   :: 'NFData' a => 'IO' a -> 'Benchmarkable'
+-- 'whnfIO' ::               'IO' a -> 'Benchmarkable'
 -- @
+--
+-- In certain corner cases, you may find it useful to use the following
+-- variants, which take the input as a separate argument:
+--
+-- @
+-- 'nfAppIO'   :: 'NFData' b => (a -> 'IO' b) -> a -> 'Benchmarkable'
+-- 'whnfAppIO' ::               (a -> 'IO' b) -> a -> 'Benchmarkable'
+-- @
+--
+-- This is useful when the bulk of the work performed by the function is
+-- not bound by IO, but rather by pure computations that may optimize away if
+-- the argument is known statically, as in 'nfIO'/'whnfIO'.
 
 -- $pure
 --
diff --git a/Criterion/Monad/Internal.hs b/Criterion/Monad/Internal.hs
--- a/Criterion/Monad/Internal.hs
+++ b/Criterion/Monad/Internal.hs
@@ -18,8 +18,9 @@
     ) where
 
 import Control.Monad.Catch (MonadThrow, MonadCatch, MonadMask)
+import qualified Control.Monad.Fail as Fail (MonadFail(..))
 import Control.Monad.Reader (MonadReader(..), ReaderT)
-import Control.Monad.Trans (MonadIO)
+import Control.Monad.Trans (MonadIO, lift)
 import Criterion.Types (Config)
 import Data.IORef (IORef)
 import Prelude ()
@@ -40,3 +41,9 @@
     ask     = config `fmap` Criterion ask
     local f = Criterion . local fconfig . runCriterion
       where fconfig c = c { config = f (config c) }
+
+-- ReaderT has a MonadFail instance, but only on GHC 8.0+, so I inline the
+-- fail implementation for ReaderT here to compensate. (Otherwise, I'd just
+-- derive this instance.)
+instance Fail.MonadFail Criterion where
+  fail = Criterion . lift . Fail.fail
diff --git a/Criterion/Types.hs b/Criterion/Types.hs
--- a/Criterion/Types.hs
+++ b/Criterion/Types.hs
@@ -61,6 +61,8 @@
     , whnf
     , nfIO
     , whnfIO
+    , nfAppIO
+    , whnfAppIO
     -- * Result types
     , Outliers(..)
     , OutlierEffect(..)
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,10 @@
+1.5.1.0
+
+* Add a `MonadFail Criterion` instance.
+
+* Add some documentation in `Criterion.Main` about `criterion-measurement`'s
+  new `nfAppIO` and `whnfAppIO` functions, which `criterion` reexports.
+
 1.5.0.0
 
 * Move the measurement functionality of `criterion` into a standalone package,
diff --git a/criterion.cabal b/criterion.cabal
--- a/criterion.cabal
+++ b/criterion.cabal
@@ -1,5 +1,5 @@
 name:           criterion
-version:        1.5.0.0
+version:        1.5.1.0
 synopsis:       Robust, reliable performance measurement and analysis
 license:        BSD3
 license-file:   LICENSE
@@ -86,10 +86,11 @@
     cassava >= 0.3.0.0,
     code-page,
     containers,
-    criterion-measurement,
+    criterion-measurement >= 0.1.1.0 && < 0.2,
     deepseq >= 1.1.0.0,
     directory,
     exceptions >= 0.8.2 && < 0.11,
+    fail == 4.9.*,
     filepath,
     Glob >= 0.7.2,
     microstache >= 1.0.1 && < 1.1,
