diff --git a/constrictor.cabal b/constrictor.cabal
--- a/constrictor.cabal
+++ b/constrictor.cabal
@@ -1,7 +1,7 @@
 name:
   constrictor
 version:
-  0.1.1.0
+  0.1.1.1
 synopsis:
   strict versions of many things in base
 description:
@@ -34,7 +34,8 @@
   exposed-modules:
     Constrictor 
   build-depends:
-      base >=4.7 && < 5.0
+      base >=4.5 && < 5.0
+    , ghc-prim
     , transformers 
   default-language:
     Haskell2010
diff --git a/src/Constrictor.hs b/src/Constrictor.hs
--- a/src/Constrictor.hs
+++ b/src/Constrictor.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE CPP                        #-}
+{-# LANGUAGE BangPatterns               #-}
 {-# LANGUAGE DeriveFoldable             #-}
 {-# LANGUAGE DeriveFunctor              #-}
 {-# LANGUAGE DeriveGeneric              #-}
@@ -11,11 +12,16 @@
 functions in base, as well as a few functions
 that do not have lazy versions that exist in
 base (see the section on Folds).
+
+Many functions in this library have an increased
+constraint from Functor/Applicative to Monad in
+order to achieve strictness in their arguments
+and/or result.
 -}
 
 module Constrictor
   ( 
-    -- * Strict monadic functions 
+    -- * Strict 'lift-like' functions 
     (<$!>)
   , fmap'
   , liftM'
@@ -24,9 +30,8 @@
   , liftM4'
   , liftM5'
   , ap' 
-    
-    -- * Strict traversable functions
   , traverse'
+  , traverse''
   , mapM'
     
     -- * Folds
@@ -47,31 +52,51 @@
   , Ap(..)
   ) where
 
+import Prelude hiding (foldr,foldl)
+
 import Control.Applicative
 import Control.Monad (MonadPlus)
+#if MIN_VERSION_base(4,9,0)
 import Control.Monad.Fail (MonadFail)
+#endif
 import Control.Monad.Fix  (MonadFix)
-import Control.Monad.Trans.Cont (evalCont, cont)
+import Control.Monad.Trans.Cont (ContT(..), cont)
 import Data.Foldable
 import Data.Functor.Compose (Compose(..))
+import Data.Functor.Identity (runIdentity)
 import Data.Monoid hiding ((<>))
+#if MIN_VERSION_base(4,9,0)
 import Data.Semigroup
-import Data.Traversable (traverse)
+#endif
+import Data.Traversable (traverse,Traversable)
 import GHC.Generics (Generic,Generic1)
 
+#if !(MIN_VERSION_base(4,8,0))
+import Control.Applicative (WrappedMonad(..))
+#endif
+
 -- | A wrapped applicative functor.
 --   Please note that base 4.12.0.0 will include this type,
 --   and it will be removed from this library at that point.
 newtype Ap f a = Ap { getAp :: f a }
   deriving ( Alternative, Applicative
            , Enum, Eq, Foldable, Functor
-           , Generic, Generic1
-           , Monad, MonadFail, MonadFix, MonadPlus
+           , Generic
+#if MIN_VERSION_base(4,6,0)
+           , Generic1
+#endif
+           , Monad
+#if MIN_VERSION_base(4,9,0)
+           , MonadFail
+#endif
+           , MonadFix, MonadPlus
            , Num, Ord, Read, Show, Traversable
            )
 
+#if MIN_VERSION_base(4,9,0)
 instance (Applicative f, Semigroup a) => Semigroup (Ap f a) where
   (Ap x) <> (Ap y) = Ap $ liftA2 (<>) x y
+#endif
 
 instance (Applicative f, Monoid a) => Monoid (Ap f a) where
   mempty = Ap $ pure mempty
@@ -82,57 +107,81 @@
 -- | Lazy in the monoidal accumulator. Monoidal accumulation
 --   happens from left to right.
 foldlMapA :: forall t b a f. (Foldable t, Monoid b, Applicative f) => (a -> f b) -> t a -> f b
-foldlMapA f = foldr f' (pure mempty)
-  where
-    f' :: a -> f b -> f b
-    f' x y = liftA2 mappend (f x) y
+foldlMapA f = foldr (\x y -> liftA2 mappend (f x) y) (pure mempty)
 
 -- | Lazy in the monoidal accumulator. Monoidal accumulation
 --   happens from left to right.
 foldrMapA :: forall t b a f. (Foldable t, Monoid b, Applicative f) => (a -> f b) -> t a -> f b
-foldrMapA f = foldl f' (pure mempty)
-  where
-    f' :: f b -> a -> f b
-    f' y x = liftA2 (flip mappend) (f x) y
+foldrMapA f = foldl (\y x -> liftA2 (flip mappend) (f x) y) (pure mempty)
 
 -- | Strict in the monoidal accumulator.
 --   For monads strict in the left argument of bind,
 --   this will run in constant space.
 --   Monoidal accumulation happens from left to right.
 foldlMapM' :: forall t b a m. (Foldable t, Monoid b, Monad m) => (a -> m b) -> t a -> m b
-foldlMapM' f xs = foldr f' pure xs mempty
+foldlMapM' f xs = foldr f' return xs mempty
   where
   f' :: a -> (b -> m b) -> b -> m b
   f' x k bl = do
-    br <- f x
+    !br <- f x
     k $! (mappend bl br) 
 
 -- Strict in the monoidal accumulator. 
 -- Monoidal accumulation happens from left to right.
 foldrMapM' :: forall t b a m. (Foldable t, Monoid b, Monad m) => (a -> m b) -> t a -> m b
-foldrMapM' f xs = foldl f' pure xs mempty
+foldrMapM' f xs = foldl f' return xs mempty
   where
   f' :: (b -> m b) -> a -> b -> m b
   f' k x br = do
-    bl <- f x
+    !bl <- f x
     k $! (mappend bl br) 
 
 infixl 4 <$!>, `fmap'`, `liftM'`
 
--- | Strict version of 'Data.Functor.<$>'
+-- | This is 'Data.Functor.<$>', but strict in its
+-- argument and result.
+--
+-- This is re-defined in this module, and not
+-- just re-exported from @'Control.Monad'@.
+-- The reason for this is that there is no way
+-- to hide the docs for re-exports with Haddocks.
+--
+-- In the common case that one might import
+-- @'Control.Monad'@, we recommend structuring
+-- imports like so:
+--
+-- @
+-- import Control.Monad hiding ((<$!>))
+-- import Constrictor
+-- @
+--
+-- or
+--
+-- @
+-- import Control.Monad
+-- import Constrictor hiding ((<$!>))
+-- @
+--
+-- There should be no side effects (i.e.
+-- naming/scoping conflicts) introduced as a
+-- result of structuring one's imports in this way.
 (<$!>) :: Monad m => (a -> b) -> m a -> m b
 {-# INLINE (<$!>) #-}
 f <$!> m = do
-  x <- m
-  pure $! f x
+  !x <- m
+  return $! f x
 
+-- | This is 'Data.Functor.fmap', but strict in its
+-- argument and result.
+--
 -- Note this is equivalent to '<$!>',
 -- and is provided for convenience.
 fmap' :: Monad m => (a -> b) -> m a -> m b
 {-# INLINE fmap' #-}
 fmap' = (<$!>)
 
--- | Strict version of 'Control.Monad.liftM'.
+-- | This is 'Control.Monad.liftM', but strict in its
+-- argument and result.
 --
 -- Note this is equivalent to '<$!>',
 -- and is provided for convenience.
@@ -140,63 +189,82 @@
 {-# INLINE liftM' #-} 
 liftM' = (<$!>)
 
--- | Strict version of 'Control.Monad.liftM2'.
+-- | This is 'Control.Monad.liftM2', but strict in its
+-- arguments and result.
 liftM2' :: Monad m => (a -> b -> c) -> m a -> m b -> m c
 {-# INLINE liftM2' #-}
 liftM2' f a b = do
-  x <- a
-  y <- b
-  pure $! f x y
+  !x <- a
+  !y <- b
+  return $! f x y
 
--- | Strict version of 'Control.Monad.liftM3'.
+-- | This is 'Control.Monad.liftM3', but strict in its
+-- arguments and result.
 liftM3' :: Monad m => (a -> b -> c -> d) -> m a -> m b -> m c -> m d
 {-# INLINE liftM3' #-}
 liftM3' f a b c = do
-  x <- a
-  y <- b
-  z <- c
-  pure $! f x y z
+  !x <- a
+  !y <- b
+  !z <- c
+  return $! f x y z
 
--- | Strict version of 'Control.Monad.liftM4'.
+-- | This is 'Control.Monad.liftM4', but strict in its
+-- arguments and result.
 liftM4' :: Monad m => (a -> b -> c -> d -> e) -> m a -> m b -> m c -> m d -> m e 
 {-# INLINE liftM4' #-}
 liftM4' f a b c d = do
-  x <- a
-  y <- b
-  z <- c
-  u <- d
-  pure $! f x y z u
+  !x <- a
+  !y <- b
+  !z <- c
+  !u <- d
+  return $! f x y z u
 
--- | Strict version of 'Control.Monad.liftM5'.
+-- | This is 'Control.Monad.liftM5', but strict in its
+-- arguments and result.
 liftM5' :: Monad m => (a -> b -> c -> d -> e -> f) -> m a -> m b -> m c -> m d -> m e -> m f
 {-# INLINE liftM5' #-}
 liftM5' f a b c d e = do
-  x <- a
-  y <- b
-  z <- c
-  u <- d
-  v <- e
-  pure $! f x y z u v
+  !x <- a
+  !y <- b
+  !z <- c
+  !u <- d
+  !v <- e
+  return $! f x y z u v
 
--- | Strict version of 'Control.Monad.ap'
+-- | This is 'Control.Monad.ap', but strict in its
+-- arguments and result.
 ap' :: Monad m => m (a -> b) -> m a -> m b
 {-# INLINE ap' #-}
 ap' m1 m2 = do
-  f <- m1
-  x <- m2
-  pure $! f x
+  !f <- m1
+  !x <- m2
+  return $! f x
 
 -- | Strict version of 'Data.Traversable.traverse'.
 traverse' :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
 {-# INLINE traverse' #-}
-traverse' f = fmap evalCont . getCompose . traverse (Compose . fmap (\a -> cont $ \k -> k $! a) . f)
+traverse' f = fmap (runIdentity . evalContT) . getCompose . traverse (Compose . fmap (\a -> cont $ \k -> k $! a) . f)
 
+-- | Stricter version of 'Data.Traversable.traverse'.
+traverse'' :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)
+{-# INLINE traverse'' #-}
+traverse'' f = fmap' (runIdentity . evalContT) . getCompose . traverse (Compose . fmap' (\a -> cont $ \k -> k $! a) . f)
+
+-- this is copied from transformers for backwards compatibility
+evalContT :: (Monad m) => ContT r m r -> m r
+evalContT m = runContT m return
+{-# INLINE evalContT #-}
+
 -- | Strict version of 'Control.Monad.mapM'.
 --
 -- This is just 'traverse'' specialised to 'Monad'.
 mapM' :: (Traversable t, Monad m) => (a -> m b) -> t a-> m (t b)
 {-# INLINE mapM' #-}
+#if MIN_VERSION_base(4,8,0)
 mapM' = traverse'
+#else
+mapM' f xs = unwrapMonad (traverse' (\x -> WrapMonad (f x)) xs)
+#endif
 
 -- The INLINES used below allow more list functions to fuse.
 -- See Trac #9848.
