diff --git a/CHANGES.txt b/CHANGES.txt
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,7 @@
 Changelog for Extra
 
+1.5.3
+    Add readMaybe, readEither
 1.5.2
     Add errorWithoutStackTrace to Control.Exception.Extra
 1.5.1
diff --git a/Generate.hs b/Generate.hs
--- a/Generate.hs
+++ b/Generate.hs
@@ -6,18 +6,18 @@
 import Data.List.Extra
 import System.IO.Extra
 import Control.Monad.Extra
-import Control.Applicative
 import System.FilePath
 import System.Directory
 import Data.Char
 import Data.Maybe
+import Data.Functor
 import Prelude
 
 
 main :: IO ()
 main = do
     src <- readFile "extra.cabal"
-    mods <- return $ filter (isSuffixOf ".Extra") $ map trim $ lines src
+    let mods = filter (isSuffixOf ".Extra") $ map trim $ lines src
     ifaces <- forM mods $ \mod -> do
         src <- readFile $ joinPath ("src" : split (== '.') mod) <.> "hs"
         let funcs = filter validIdentifier $ takeWhile (/= "where") $
diff --git a/extra.cabal b/extra.cabal
--- a/extra.cabal
+++ b/extra.cabal
@@ -1,7 +1,7 @@
 cabal-version:      >= 1.18
 build-type:         Simple
 name:               extra
-version:            1.5.2
+version:            1.5.3
 license:            BSD3
 license-file:       LICENSE
 category:           Development
@@ -58,6 +58,7 @@
         System.IO.Extra
         System.Process.Extra
         System.Time.Extra
+        Text.Read.Extra
 
 test-suite extra-test
     type:            exitcode-stdio-1.0
diff --git a/src/Control/Concurrent/Extra.hs b/src/Control/Concurrent/Extra.hs
--- a/src/Control/Concurrent/Extra.hs
+++ b/src/Control/Concurrent/Extra.hs
@@ -28,6 +28,9 @@
 import Control.Exception.Extra
 import Control.Monad.Extra
 import Data.Maybe
+import Data.Either.Extra
+import Data.Functor
+import Prelude
 
 
 -- | On GHC 7.6 and above with the @-threaded@ flag, brackets a call to 'setNumCapabilities'.
@@ -133,7 +136,7 @@
 
 -- | Create a new 'Lock'.
 newLock :: IO Lock
-newLock = fmap Lock $ newMVar ()
+newLock = Lock <$> newMVar ()
 
 -- | Perform some operation while holding 'Lock'. Will prevent all other
 --   operations from using the 'Lock' while the action is ongoing.
@@ -224,7 +227,7 @@
 -- | Write a value into the Barrier, releasing anyone at 'waitBarrier'.
 --   Any subsequent attempts to signal the 'Barrier' will throw an exception.
 signalBarrier :: Barrier a -> a -> IO ()
-signalBarrier (Barrier var) v = mask_ $ do -- use mask so never in an inconsistent state
+signalBarrier (Barrier var) v = mask_ $ -- use mask so never in an inconsistent state
     join $ modifyVar var $ \x -> case x of
         Left bar -> return (Right v, putMVar bar ())
         Right res -> error "Control.Concurrent.Extra.signalBarrier, attempt to signal a barrier that has already been signaled"
@@ -247,4 +250,4 @@
 -- | A version of 'waitBarrier' that never blocks, returning 'Nothing'
 --   if the barrier has not yet been signaled.
 waitBarrierMaybe :: Barrier a -> IO (Maybe a)
-waitBarrierMaybe (Barrier bar) = fmap (either (const Nothing) Just) $ readVar bar
+waitBarrierMaybe (Barrier bar) = eitherToMaybe <$> readVar bar
diff --git a/src/Control/Exception/Extra.hs b/src/Control/Exception/Extra.hs
--- a/src/Control/Exception/Extra.hs
+++ b/src/Control/Exception/Extra.hs
@@ -20,6 +20,8 @@
 import Control.Exception
 import Control.Monad
 import Data.List.Extra
+import Data.Functor
+import Prelude
 
 
 -- | Fully evaluate an input String. If the String contains embedded exceptions it will produce @\<Exception\>@.
@@ -34,7 +36,7 @@
     case r of
         Left e -> return "<Exception>"
         Right [] -> return []
-        Right (x:xs) -> fmap (x:) $ stringException xs
+        Right (x:xs) -> (x:) <$> stringException xs
 
 
 -- | Show a value, but if the result contains exceptions, produce
diff --git a/src/Control/Monad/Extra.hs b/src/Control/Monad/Extra.hs
--- a/src/Control/Monad/Extra.hs
+++ b/src/Control/Monad/Extra.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE UnboxedTuples #-}
 
 -- | Extra functions for "Control.Monad".
 --   These functions provide looping, list operations and booleans.
@@ -18,8 +17,8 @@
     ) where
 
 import Control.Monad
-import Control.Applicative
 import Data.Maybe
+import Control.Applicative
 import Data.Monoid
 import Prelude
 
diff --git a/src/Data/IORef/Extra.hs b/src/Data/IORef/Extra.hs
--- a/src/Data/IORef/Extra.hs
+++ b/src/Data/IORef/Extra.hs
@@ -46,7 +46,7 @@
 -- 'atomicModifyIORef' has.
 atomicWriteIORef :: IORef a -> a -> IO ()
 atomicWriteIORef ref a = do
-    x <- atomicModifyIORef ref (\_ -> (a, ()))
+    x <- atomicModifyIORef ref $ const (a, ())
     x `seq` return ()
 
 #endif
diff --git a/src/Data/List/Extra.hs b/src/Data/List/Extra.hs
--- a/src/Data/List/Extra.hs
+++ b/src/Data/List/Extra.hs
@@ -28,13 +28,13 @@
     replace, merge, mergeBy,
     ) where
 
-import Control.Applicative
 import Data.List
 import Data.Maybe
 import Data.Function
 import Data.Char
 import Data.Tuple.Extra
 import Data.Monoid
+import Data.Functor
 import Prelude
 
 
@@ -510,7 +510,7 @@
 -- > stripSuffix ""    "baz"    == Just "baz"
 -- > stripSuffix "foo" "quux"   == Nothing
 stripSuffix :: Eq a => [a] -> [a] -> Maybe [a]
-stripSuffix a b = fmap reverse $ stripPrefix (reverse a) (reverse b)
+stripSuffix a b = reverse <$> stripPrefix (reverse a) (reverse b)
 
 
 -- | Return the the string before and after the search string,
diff --git a/src/Extra.hs b/src/Extra.hs
--- a/src/Extra.hs
+++ b/src/Extra.hs
@@ -54,6 +54,9 @@
     -- * System.Time.Extra
     -- | Extra functions available in @"System.Time.Extra"@.
     Seconds, sleep, timeout, subtractTime, showDuration, offsetTime, offsetTimeIncrease, duration,
+    -- * Text.Read.Extra
+    -- | Extra functions available in @"Text.Read.Extra"@.
+    readEither, readMaybe,
     ) where
 
 import Control.Concurrent.Extra
@@ -72,3 +75,4 @@
 import System.IO.Extra
 import System.Process.Extra
 import System.Time.Extra
+import Text.Read.Extra
diff --git a/src/System/Environment/Extra.hs b/src/System/Environment/Extra.hs
--- a/src/System/Environment/Extra.hs
+++ b/src/System/Environment/Extra.hs
@@ -13,6 +13,7 @@
 #if __GLASGOW_HASKELL__ < 706
 import Control.Exception.Extra
 import System.IO.Error
+import Data.Functor
 
 -- | Alias for 'getProgName' in GHC 7.4 and below, otherwise
 --   returns the absolute pathname of the current executable.
@@ -21,5 +22,5 @@
 
 -- | Return the value of the environment variable var, or Nothing if there is no such value.
 lookupEnv :: String -> IO (Maybe String)
-lookupEnv x = catchBool isDoesNotExistError (fmap Just $ getEnv x) (const $ return Nothing)
+lookupEnv x = catchBool isDoesNotExistError (Just <$> getEnv x) (const $ return Nothing)
 #endif
diff --git a/src/System/Process/Extra.hs b/src/System/Process/Extra.hs
--- a/src/System/Process/Extra.hs
+++ b/src/System/Process/Extra.hs
@@ -11,6 +11,8 @@
 import System.IO.Extra
 import System.Process
 import System.Exit
+import Data.Functor
+import Prelude
 
 
 -- | A version of 'system' that also captures the output, both 'stdout' and 'stderr'.
@@ -20,7 +22,7 @@
     exit <- withFile file WriteMode $ \h -> do
         (_, _, _, pid) <- createProcess (shell x){std_out=UseHandle h, std_err=UseHandle h}
         waitForProcess pid
-    fmap (exit,) $ readFile' file
+    (exit,) <$> readFile' file
 
 
 -- | A version of 'system' that throws an error if the 'ExitCode' is not 'ExitSuccess'.
diff --git a/src/System/Time/Extra.hs b/src/System/Time/Extra.hs
--- a/src/System/Time/Extra.hs
+++ b/src/System/Time/Extra.hs
@@ -68,7 +68,7 @@
         handleBool (== ex) 
                    (const $ return Nothing)
                    (bracket (forkIOWithUnmask $ \unmask -> unmask $ sleep n >> throwTo pid ex)
-                            (killThread)
+                            killThread
                             (\_ -> fmap Just f))
 
 
diff --git a/src/Text/Read/Extra.hs b/src/Text/Read/Extra.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Read/Extra.hs
@@ -0,0 +1,38 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -fno-warn-duplicate-exports #-}
+
+-- | This module provides "Text.Read" with functions added in later versions.
+module Text.Read.Extra(
+    module Text.Read,
+    readEither, readMaybe
+    ) where
+
+import Text.Read
+
+#if __GLASGOW_HASKELL__ < 706
+
+import Text.ParserCombinators.ReadP as P
+
+-- | Parse a string using the 'Read' instance.
+-- Succeeds if there is exactly one valid result.
+-- A 'Left' value indicates a parse error.
+readEither :: Read a => String -> Either String a
+readEither s =
+  case [ x | (x,"") <- readPrec_to_S read' minPrec s ] of
+    [x] -> Right x
+    []  -> Left "Prelude.read: no parse"
+    _   -> Left "Prelude.read: ambiguous parse"
+ where
+  read' =
+    do x <- readPrec
+       lift P.skipSpaces
+       return x
+
+-- | Parse a string using the 'Read' instance.
+-- Succeeds if there is exactly one valid result.
+readMaybe :: Read a => String -> Maybe a
+readMaybe s = case readEither s of
+                Left _  -> Nothing
+                Right a -> Just a
+
+#endif
diff --git a/test/TestUtil.hs b/test/TestUtil.hs
--- a/test/TestUtil.hs
+++ b/test/TestUtil.hs
@@ -54,7 +54,9 @@
 erroneousIO x = unsafePerformIO $ fmap isLeft $ try_ $ evaluate . length . show =<< x
 
 (====) :: (Show a, Eq a) => a -> a -> Bool
-a ==== b = if a == b then True else error $ "Not equal!\n" ++ show a ++ "\n" ++ show b
+a ==== b
+    | a == b = True
+    | otherwise = error $ "Not equal!\n" ++ show a ++ "\n" ++ show b
 
 #if __GLASGOW_HASKELL__ < 707
 instance Eq ErrorCall where
@@ -101,4 +103,4 @@
     arbitrary = fmap ModifiedJulianDay arbitrary
 
 instance Arbitrary DiffTime where
-    arbitrary = fmap realToFrac $ choose (0 :: Double, 86401)
+    arbitrary = realToFrac <$> choose (0 :: Double, 86401)
