diff --git a/ClassyPrelude.hs b/ClassyPrelude.hs
--- a/ClassyPrelude.hs
+++ b/ClassyPrelude.hs
@@ -12,6 +12,8 @@
     , empty
     , append
     , (++)
+      -- ** Monad
+    , module Control.Monad
       -- * Non-standard
       -- ** List-like classes
     , map
@@ -27,6 +29,9 @@
     , toList
     , mapM
     , mapM_
+    , forM
+    , forM_
+    , replicateM
     , stripPrefix
     , isPrefixOf
     , stripSuffix
@@ -48,6 +53,8 @@
     , reverse
     , readMay
     , replicate
+    , encodeUtf8
+    , decodeUtf8
       -- ** Map-like
     , lookup
     , insert
@@ -77,6 +84,7 @@
 
 import qualified Prelude
 import qualified Data.Maybe
+import Control.Monad (when, unless, void, liftM, ap, forever)
 
 import CorePrelude
 import ClassyPrelude.Classes
@@ -166,3 +174,9 @@
 
 asVector :: Vector a -> Vector a
 asVector = id
+
+forM :: CanMapMFunc ci mco m i o => ci -> (i -> m o) -> mco
+forM = flip mapM
+
+forM_ :: (Monad m, CanMapM_Func ci i) => ci -> (i -> m o) -> m ()
+forM_ = flip mapM_
diff --git a/ClassyPrelude/ByteString.hs b/ClassyPrelude/ByteString.hs
--- a/ClassyPrelude/ByteString.hs
+++ b/ClassyPrelude/ByteString.hs
@@ -53,3 +53,9 @@
 
 instance CanReplicate ByteString Word8 Prelude.Int where
     replicate = S.replicate
+
+instance CanStripSuffix ByteString where
+    stripSuffix x y
+        | x `S.isSuffixOf` y = Prelude.Just (S.take (S.length y Prelude.- S.length x) y)
+        | Prelude.otherwise = Prelude.Nothing
+    isSuffixOf = S.isSuffixOf
diff --git a/ClassyPrelude/Classes.hs b/ClassyPrelude/Classes.hs
--- a/ClassyPrelude/Classes.hs
+++ b/ClassyPrelude/Classes.hs
@@ -28,9 +28,16 @@
     filter :: (i -> Prelude.Bool) -> f
 class CanFilterFunc ci co i | ci -> i co where
     filterFunc :: (i -> Prelude.Bool) -> ci -> co
-instance (CanFilterFunc ci co i) => CanFilter (ci -> co) i where
+instance (CanFilterFunc ci co i, ci ~ co) => CanFilter (ci -> co) i where
     filter = filterFunc
 
+class CanFilterM f m i where
+    filterM :: (i -> m Prelude.Bool) -> f
+class CanFilterMFunc c i | c -> i where
+    filterMFunc :: Monad m => (i -> m Prelude.Bool) -> c -> m c
+instance (CanFilterMFunc ci i, m ci ~ mco, Monad m) => CanFilterM (ci -> mco) m i where
+    filterM = filterMFunc
+
 class CanLength c len | c -> len where
     length :: c -> len
 
@@ -58,6 +65,9 @@
 instance (Monad m, CanMapM_Func ci i, r ~ m ()) => CanMapM_ (ci -> r) m i where
     mapM_ = mapM_Func
 
+class CanReplicateM c i len | c -> i len where
+    replicateM :: Monad m => len -> m i -> m c
+
 class CanLookup c k v | c -> k v where
     lookup :: k -> c -> Prelude.Maybe v
 
@@ -118,7 +128,15 @@
 class CanWords t where
     words :: t -> [t]
     unwords :: [t] -> t
-    lines :: t -> [t]
+
+class CanLines f where
+    lines :: f
+class CanLinesFunc t where
+    linesFunc :: t -> [t]
+instance (CanLinesFunc t, out ~ [t]) => CanLines (t -> out) where
+    lines = linesFunc
+
+class CanUnlines t where
     unlines :: [t] -> t
 
 class CanSplit c i | c -> i where
@@ -140,3 +158,20 @@
 class CanToChunks c i | c -> i, i -> c where
     toChunks :: c -> [i]
     fromChunks :: [i] -> c
+
+class CanEncodeUtf8 f where
+    encodeUtf8 :: f
+class CanEncodeUtf8Func ci co | co -> ci, ci -> co where
+    encodeUtf8Func :: ci -> co
+instance CanEncodeUtf8Func ci co => CanEncodeUtf8 (ci -> co) where
+    encodeUtf8 = encodeUtf8Func
+
+class CanDecodeUtf8 f where
+    decodeUtf8 :: f
+-- | Note: implementations should ensure that @decodeUtf8Func@ is a total
+-- function. As such, the standard @decodeUtf8@ provided by the text package
+-- should not be used, but instead @decodeUtf8With lenientDecode@.
+class CanDecodeUtf8Func ci co | co -> ci, ci -> co where
+    decodeUtf8Func :: ci -> co
+instance CanDecodeUtf8Func ci co => CanDecodeUtf8 (ci -> co) where
+    decodeUtf8 = decodeUtf8Func
diff --git a/ClassyPrelude/LByteString.hs b/ClassyPrelude/LByteString.hs
--- a/ClassyPrelude/LByteString.hs
+++ b/ClassyPrelude/LByteString.hs
@@ -60,3 +60,9 @@
 instance CanToChunks LByteString Data.ByteString.ByteString where
     toChunks = L.toChunks
     fromChunks = L.fromChunks
+
+instance CanStripSuffix LByteString where
+    stripSuffix x y
+        | x `L.isSuffixOf` y = Prelude.Just (L.take (L.length y Prelude.- L.length x) y)
+        | Prelude.otherwise = Prelude.Nothing
+    isSuffixOf = L.isSuffixOf
diff --git a/ClassyPrelude/LText.hs b/ClassyPrelude/LText.hs
--- a/ClassyPrelude/LText.hs
+++ b/ClassyPrelude/LText.hs
@@ -12,6 +12,9 @@
 import qualified Data.Text.Lazy as TL
 import Data.Int (Int64)
 import qualified Data.Text
+import qualified Data.Text.Lazy.Encoding
+import qualified Data.Text.Encoding.Error
+import Data.ByteString.Lazy (ByteString)
 
 type LText = TL.Text
 
@@ -45,7 +48,11 @@
 instance CanWords LText where
     words = TL.words
     unwords = TL.unwords
-    lines = TL.lines
+
+instance CanLinesFunc LText where
+    linesFunc = TL.lines
+
+instance CanUnlines LText where
     unlines = TL.unlines
 
 instance CanSplit LText Char where
@@ -73,3 +80,8 @@
 instance CanToChunks LText Data.Text.Text where
     toChunks = TL.toChunks
     fromChunks = TL.fromChunks
+
+instance CanEncodeUtf8Func LText ByteString where
+    encodeUtf8Func = Data.Text.Lazy.Encoding.encodeUtf8
+instance CanDecodeUtf8Func ByteString LText where
+    decodeUtf8Func = Data.Text.Lazy.Encoding.decodeUtf8With Data.Text.Encoding.Error.lenientDecode
diff --git a/ClassyPrelude/List.hs b/ClassyPrelude/List.hs
--- a/ClassyPrelude/List.hs
+++ b/ClassyPrelude/List.hs
@@ -8,6 +8,7 @@
 import Prelude ((.))
 import ClassyPrelude.Classes
 import qualified Data.List
+import qualified Control.Monad
 
 instance CanMapFunc [a] [b] a b where
     mapFunc = Prelude.map
@@ -15,6 +16,8 @@
     concatMapFunc = Prelude.concatMap
 instance CanFilterFunc [a] [a] a where
     filterFunc = Prelude.filter
+instance CanFilterMFunc [a] a where
+    filterMFunc = Control.Monad.filterM
 instance CanLength [a] Prelude.Int where
     length = Prelude.length
 instance CanSingleton [a] a where
@@ -55,7 +58,11 @@
 instance (c ~ Prelude.Char) => CanWords [c] where
     words = Prelude.words
     unwords = Prelude.unwords
-    lines = Prelude.lines
+
+instance (c ~ Prelude.Char) => CanLinesFunc [c] where
+    linesFunc = Prelude.lines
+
+instance (c ~ Prelude.Char) => CanUnlines [c] where
     unlines = Prelude.unlines
 
 instance Prelude.Eq a => CanIsInfixOf [a] where
@@ -66,3 +73,6 @@
 
 instance CanReplicate [i] i Prelude.Int where
     replicate = Prelude.replicate
+
+instance CanReplicateM [a] a Prelude.Int where
+    replicateM = Control.Monad.replicateM
diff --git a/ClassyPrelude/Text.hs b/ClassyPrelude/Text.hs
--- a/ClassyPrelude/Text.hs
+++ b/ClassyPrelude/Text.hs
@@ -11,6 +11,9 @@
 import ClassyPrelude.Classes
 import Data.Text (Text)
 import qualified Data.Text as T
+import qualified Data.Text.Encoding
+import qualified Data.Text.Encoding.Error
+import Data.ByteString (ByteString)
 
 instance CanMapFunc Text Text Char Char where
     mapFunc = T.map
@@ -44,7 +47,11 @@
 instance CanWords Text where
     words = T.words
     unwords = T.unwords
-    lines = T.lines
+
+instance CanLinesFunc Text where
+    linesFunc = T.lines
+
+instance CanUnlines Text where
     unlines = T.unlines
 
 instance CanSplit Text Char where
@@ -65,3 +72,8 @@
 
 instance CanReplicate Text Text Prelude.Int where
     replicate = T.replicate
+
+instance CanEncodeUtf8Func Text ByteString where
+    encodeUtf8Func = Data.Text.Encoding.encodeUtf8
+instance CanDecodeUtf8Func ByteString Text where
+    decodeUtf8Func = Data.Text.Encoding.decodeUtf8With Data.Text.Encoding.Error.lenientDecode
diff --git a/ClassyPrelude/Vector.hs b/ClassyPrelude/Vector.hs
--- a/ClassyPrelude/Vector.hs
+++ b/ClassyPrelude/Vector.hs
@@ -18,6 +18,8 @@
     concatMapFunc = V.concatMap
 instance CanFilterFunc (Vector a) (Vector a) a where
     filterFunc = V.filter
+instance CanFilterMFunc (Vector a) a where
+    filterMFunc = V.filterM
 instance CanLength (Vector a) Prelude.Int where
     length = V.length
 instance CanSingleton (Vector a) a where
@@ -51,3 +53,6 @@
 
 instance CanReplicate (Vector a) a Prelude.Int where
     replicate = V.replicate
+
+instance CanReplicateM (Vector a) a Prelude.Int where
+    replicateM = V.replicateM
diff --git a/classy-prelude.cabal b/classy-prelude.cabal
--- a/classy-prelude.cabal
+++ b/classy-prelude.cabal
@@ -1,5 +1,5 @@
 name:                classy-prelude
-version:             0.3.1
+version:             0.4.0
 synopsis:            A typeclass-based Prelude.
 description:         Focuses on using common typeclasses when possible, and creating new ones to avoid name clashing. Exposes many recommended datastructures (Map, ByteString, etc) directly without requiring long import lists and qualified modules.
 homepage:            https://github.com/snoyberg/classy-prelude
diff --git a/test/main.hs b/test/main.hs
--- a/test/main.hs
+++ b/test/main.hs
@@ -11,6 +11,8 @@
 import Prelude (asTypeOf, undefined, fromIntegral)
 import qualified Prelude
 import Control.Monad.Trans.Writer (tell, Writer, runWriter)
+import Data.Maybe (isJust)
+import Data.Functor.Identity (runIdentity)
 
 dictionaryProps
     :: ( CanInsertVal a Int Char
@@ -90,6 +92,21 @@
     prop "filter f c == pack (filter f (unpack c))" $ \c ->
         (repack (filter f (c `asTypeOf` dummy)) `asTypeOf` dummy) == pack (filter f (unpack c))
 
+filterMProps :: ( CanPack a i
+                , Show a
+                , Arbitrary a
+                , Eq a
+                , CanFilterMFunc a i
+                )
+             => a
+             -> (i -> Bool)
+             -> Spec
+filterMProps dummy f' = do
+    prop "filterM f c == fmap pack (filterM f (unpack c))" $ \c ->
+        runIdentity (fmap repack (filterM f (c `asTypeOf` dummy))) `asTypeOf` dummy == runIdentity (fmap pack (filterM f (unpack c)))
+  where
+    f = return . f'
+
 lengthProps :: ( Show a
                , Eq a
                , Arbitrary a
@@ -178,6 +195,42 @@
     prop "fromChunks . return . concat . toChunks == id" $ \a ->
         fromChunks [concat $ toChunks (a `asTypeOf` dummy)] == a
 
+stripSuffixProps :: ( Eq a
+                    , Monoid a
+                    , CanStripSuffix a
+                    , Show a
+                    , Arbitrary a
+                    ) => a -> Spec
+stripSuffixProps dummy = do
+    prop "stripSuffix y (x ++ y) == Just x" $ \x y ->
+        stripSuffix y (x ++ y) == Just (x `asTypeOf` dummy)
+    prop "isJust (stripSuffix x y) == isSuffixOf x y" $ \x y ->
+        isJust (stripSuffix x y) == isSuffixOf x (y `asTypeOf` dummy)
+
+replicateMProps :: ( Eq c
+                   , Show len
+                   , Arbitrary len
+                   , CanReplicateM c i len
+                   , CanReplicate c i len
+                   , Show i
+                   , Arbitrary i
+                   , Integral len
+                   ) => c -> Spec
+replicateMProps dummy = do
+    prop "runIdentity (replicateM i (return x)) == replicate i x" $ \i' x ->
+        let i = i' `mod` 20
+         in runIdentity (replicateM i (return x)) == (replicate i x `asTypeOf` dummy)
+
+utf8Props :: ( Eq t
+             , Show t
+             , Arbitrary t
+             , CanEncodeUtf8Func t b
+             , CanDecodeUtf8Func b t
+             ) => t -> Spec
+utf8Props dummy = do
+    prop "decodeUtf8 . encodeUtf8 == id" $ \t ->
+        decodeUtf8 (encodeUtf8 t) == (t `asTypeOf` dummy)
+
 main :: IO ()
 main = hspec $ do
     describe "dictionary" $ do
@@ -209,6 +262,9 @@
         describe "Data.Text.Lazy" $ filterProps (undefined :: LText) (< 'A')
         describe "Data.Map" $ filterProps (undefined :: Map Int Char) (\(i, _) -> i < 20)
         describe "Data.HashMap" $ filterProps (undefined :: HashMap Int Char) (\(i, _) -> i < 20)
+    describe "filterM" $ do
+        describe "list" $ filterMProps (undefined :: [Int]) (< 20)
+        describe "Data.Vector" $ filterMProps (undefined :: Vector Int) (< 20)
     describe "length" $ do
         describe "list" $ lengthProps (undefined :: [Int])
         describe "Data.Vector" $ lengthProps (undefined :: Vector Int)
@@ -246,6 +302,17 @@
     describe "chunks" $ do
         describe "ByteString" $ chunkProps (asLByteString undefined)
         describe "Text" $ chunkProps (asLText undefined)
+    describe "stripSuffix" $ do
+        describe "Text" $ stripSuffixProps (undefined :: Text)
+        describe "LText" $ stripSuffixProps (undefined :: LText)
+        describe "ByteString" $ stripSuffixProps (undefined :: ByteString)
+        describe "LByteString" $ stripSuffixProps (undefined :: LByteString)
+    describe "replicateM" $ do
+        describe "list" $ replicateMProps (undefined :: [Int])
+        describe "Vector" $ replicateMProps (undefined :: Vector Int)
+    describe "encode/decode UTF8" $ do
+        describe "Text" $ utf8Props (undefined :: Text)
+        describe "LText" $ utf8Props (undefined :: LText)
 
 instance Arbitrary (Map Int Char) where
     arbitrary = fromList <$> arbitrary
