diff --git a/CHANGES b/CHANGES
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,11 @@
-0.1.4: January 14, 2014
+0.1.5: March 10, 2018
+  * Add support for GHC 8.4.1. Thanks, Andrés Sicard-Ramírez.
+  * Clean up QuickCheck generators, and prevent them from blowing up.
+    Thanks, Harry Garrood.
+  * Generalize functions for combining multiple boxes from lists to
+    `Foldable` containers.
+
+0.1.4: January 14, 2015
   * Require Cabal >= 1.9.2
   * Require CPP
   * Only require OverloadedStrings for GHC
diff --git a/Text/PrettyPrint/Boxes.hs b/Text/PrettyPrint/Boxes.hs
--- a/Text/PrettyPrint/Boxes.hs
+++ b/Text/PrettyPrint/Boxes.hs
@@ -1,31 +1,12 @@
 {-# LANGUAGE CPP #-}
-#ifndef MIN_VERSION_base
--- These are not precise, but allow the module to be built without cabal.
-#if __GLASGOW_HASKELL__ >= 709
-#define MIN_VERSION_base(major1,major2,minor) (((major1) <= 4) && ((major2) <= 8))
-#elif __GLASGOW_HASKELL__ >= 707
-#define MIN_VERSION_base(major1,major2,minor) (((major1) <= 4) && ((major2) <= 7))
-#elif __GLASGOW_HASKELL__ >= 706
-#define MIN_VERSION_base(major1,major2,minor) (((major1) <= 4) && ((major2) <= 6))
-#else
-#define MIN_VERSION_base(major1,major2,minor) 0
-#endif
-#endif
-
-#ifdef __GLASGOW_HASKELL__
-#define OVERLOADED_STRINGS 1
-#endif
-
-#ifdef OVERLOADED_STRINGS
-{-# LANGUAGE OverloadedStrings #-}
-#endif
+#include "boxes.h"
 
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Text.PrettyPrint.Boxes
 -- Copyright   :  (c) Brent Yorgey 2009
 -- License     :  BSD-style (see LICENSE)
--- Maintainer  :  byorgey@cis.upenn.edu
+-- Maintainer  :  David.Feuer@gmail.com
 -- Stability   :  experimental
 -- Portability :  portable
 --
@@ -97,9 +78,15 @@
 
     ) where
 
-#if MIN_VERSION_base(4,8,0)
+#if MIN_VERSION_base(4,11,0)
+import Prelude hiding ( (<>), Word )
+#elif MIN_VERSION_base(4,8,0)
 import Prelude hiding (Word)
+#else
+import Data.Foldable (Foldable (foldr))
+import Prelude hiding (foldr)
 #endif
+import Data.Foldable (toList)
 
 #if MIN_VERSION_base(4,4,0)
 import Data.String (words, unwords)
@@ -213,35 +200,46 @@
 t /+/ b = vcat left [t, emptyBox 1 0, b]
 
 -- | Glue a list of boxes together horizontally, with the given alignment.
-hcat :: Alignment -> [Box] -> Box
-hcat a bs = Box h w (Row $ map (alignVert a h) bs)
-  where h = maximum . (0:) . map rows $ bs
-        w = sum . map cols $ bs
+hcat :: Foldable f => Alignment -> f Box -> Box
+hcat a bs = Box h w (Row $ map (alignVert a h) bsl)
+  where
+    (w, h) = sumMax cols 0 rows bsl
+    bsl = toList bs
 
 -- | @hsep sep a bs@ lays out @bs@ horizontally with alignment @a@,
 --   with @sep@ amount of space in between each.
-hsep :: Int -> Alignment -> [Box] -> Box
+hsep :: Foldable f => Int -> Alignment -> f Box -> Box
 hsep sep a bs = punctuateH a (emptyBox 0 sep) bs
 
 -- | Glue a list of boxes together vertically, with the given alignment.
-vcat :: Alignment -> [Box] -> Box
-vcat a bs = Box h w (Col $ map (alignHoriz a w) bs)
-  where h = sum . map rows $ bs
-        w = maximum . (0:) . map cols $ bs
+vcat :: Foldable f => Alignment -> f Box -> Box
+vcat a bs = Box h w (Col $ map (alignHoriz a w) bsl)
+  where
+    (h, w) = sumMax rows 0 cols bsl
+    bsl = toList bs
 
+-- Calculate a sum and a maximum over a list in one pass. If the list is
+-- empty, the maximum is reported as the given default. This would
+-- normally be done using the foldl library, but we don't want that
+-- dependency.
+sumMax :: (Num n, Ord b, Foldable f) => (a -> n) -> b -> (a -> b) -> f a -> (n, b)
+sumMax f defaultMax g as = foldr go (,) as 0 defaultMax
+  where
+    go a r n b = (r $! f a + n) $! g a `max` b
+
 -- | @vsep sep a bs@ lays out @bs@ vertically with alignment @a@,
 --   with @sep@ amount of space in between each.
-vsep :: Int -> Alignment -> [Box] -> Box
-vsep sep a bs = punctuateV a (emptyBox sep 0) bs
+vsep :: Foldable f => Int -> Alignment -> f Box -> Box
+vsep sep a bs = punctuateV a (emptyBox sep 0) (toList bs)
 
 -- | @punctuateH a p bs@ horizontally lays out the boxes @bs@ with a
 --   copy of @p@ interspersed between each.
-punctuateH :: Alignment -> Box -> [Box] -> Box
-punctuateH a p bs = hcat a (intersperse p bs)
+punctuateH :: Foldable f => Alignment -> Box -> f Box -> Box
+punctuateH a p bs = hcat a (intersperse p (toList bs))
 
 -- | A vertical version of 'punctuateH'.
-punctuateV :: Alignment -> Box -> [Box] -> Box
-punctuateV a p bs = vcat a (intersperse p bs)
+punctuateV :: Foldable f => Alignment -> Box -> f Box -> Box
+punctuateV a p bs = vcat a (intersperse p (toList bs))
 
 --------------------------------------------------------------------------------
 --  Paragraph flowing  ---------------------------------------------------------
@@ -289,7 +287,7 @@
 data Line = Line { lLen :: Int, getWords :: [Word] }
 
 mkLine :: [Word] -> Line
-mkLine ws = Line (sum (map wLen ws) + length ws - 1) ws
+mkLine ws = Line (sum (map ((+1) . wLen) ws) - 1) ws
 
 startLine :: Word -> Line
 startLine = mkLine . (:[])
@@ -318,13 +316,13 @@
 --   contents and height of @bx@, horizontally aligned according to
 --   @algn@.
 alignHoriz :: Alignment -> Int -> Box -> Box
-alignHoriz a c b = Box (rows b) c $ SubBox a AlignFirst b
+alignHoriz a c b = align a AlignFirst (rows b) c b
 
 -- | @alignVert algn n bx@ creates a box of height @n@, with the
 --   contents and width of @bx@, vertically aligned according to
 --   @algn@.
 alignVert :: Alignment -> Int -> Box -> Box
-alignVert a r b = Box r (cols b) $ SubBox AlignFirst a b
+alignVert a r b = align AlignFirst a r (cols b) b
 
 -- | @align ah av r c bx@ creates an @r@ x @c@ box with the contents
 --   of @bx@, aligned horizontally according to @ah@ and vertically
diff --git a/Text/PrettyPrint/Tests.hs b/Text/PrettyPrint/Tests.hs
--- a/Text/PrettyPrint/Tests.hs
+++ b/Text/PrettyPrint/Tests.hs
@@ -1,9 +1,16 @@
 import Test.QuickCheck
 import Text.PrettyPrint.Boxes
 
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative
+#endif
 import Control.Monad
 import System.Exit (exitFailure, exitSuccess)
 
+#if MIN_VERSION_base(4,11,0)
+import Prelude hiding ((<>))
+#endif
+
 instance Arbitrary Alignment where
   arbitrary = elements [ AlignFirst
                        , AlignCenter1
@@ -12,35 +19,53 @@
                        ]
 
 instance Arbitrary Box where
-  arbitrary = do
-    (NonNegative r) <- arbitrary
-    (NonNegative c) <- arbitrary
-    liftM (Box r c) arbitrary
+  arbitrary = sized arbBox
 
+-- A sized generator for boxes. The larger the parameter is, the larger a
+-- generated Box is likely to be. This is necessary in order to avoid
+-- the tests getting stuck trying to generate ridiculously huge Box values.
+arbBox :: Int -> Gen Box
+arbBox n =
+  Box <$> nonnegative <*> nonnegative <*> arbContent n
+  where
+  nonnegative = getNonNegative <$> arbitrary
+
 instance Arbitrary Content where
-  arbitrary = oneof [ return Blank
-                    , liftM Text arbitrary
-                    , liftM Row arbitrary
-                    , liftM Col arbitrary
-                    , liftM3 SubBox arbitrary arbitrary arbitrary
-                    ]
+  arbitrary = sized arbContent
 
+-- A sized generator for Content values. The larger the parameter is, the
+-- larger a generated Content is likely to be. This is necessary in order to
+-- avoid the tests getting stuck trying to generate ridiculously huge Content
+-- values.
+--
+-- See also section 3.2 of http://www.cs.tufts.edu/%7Enr/cs257/archive/john-hughes/quick.pdf
+arbContent :: Int -> Gen Content
+arbContent 0 = pure Blank
+arbContent n =
+  oneof [ pure Blank
+        , Text <$> arbitrary
+        , Row <$> halveSize (listOf box)
+        , Col <$> halveSize (listOf box)
+        , SubBox <$> arbitrary <*> arbitrary <*> decrementSize box
+        ]
+  where
+  decrementSize = scale (\s -> max (s - 1) 0)
+  halveSize = scale (`quot` 2)
+  box = arbBox n
+
 -- extensional equivalence for Boxes
 b1 ==== b2 = render b1 == render b2
 
 prop_render_text s = render (text s) == (s ++ "\n")
 
-{-
-TODO: Find a way to enable these tests without time and space
-explosion.
-
---prop_empty_right_id b = b <> nullBox ==== b
---prop_empty_left_id b  = nullBox <> b ==== b
---prop_empty_top_id b   = nullBox // b ==== b
---prop_empty_bot_id b   = b // nullBox ==== b
--}
+prop_empty_right_id b = b <> nullBox ==== b
+prop_empty_left_id b  = nullBox <> b ==== b
+prop_empty_top_id b   = nullBox // b ==== b
+prop_empty_bot_id b   = b // nullBox ==== b
 
-main = quickCheckResult prop_render_text >>= \result ->
-          case result of
-            Success{} -> exitSuccess
-            _ -> exitFailure
+main = do
+  quickCheck prop_render_text
+  quickCheck prop_empty_right_id
+  quickCheck prop_empty_left_id
+  quickCheck prop_empty_top_id
+  quickCheck prop_empty_bot_id
diff --git a/boxes.cabal b/boxes.cabal
--- a/boxes.cabal
+++ b/boxes.cabal
@@ -1,12 +1,13 @@
 name:                boxes
-version:             0.1.4
+version:             0.1.5
 synopsis:            2D text pretty-printing library
 description:         A pretty-printing library for laying out text in
                      two dimensions, using a simple box model.
 category:            Text
 license:             BSD3
 license-file:        LICENSE
-extra-source-files:  CHANGES, README.md
+extra-source-files:  CHANGES, README.md, include/boxes.h
+
 author:              Brent Yorgey
 maintainer:          David Feuer <David.Feuer@gmail.com>
 build-type:          Simple
@@ -17,19 +18,18 @@
   build-depends:     base >= 3 && < 5, split >=0.2 && <0.3
   exposed-modules:   Text.PrettyPrint.Boxes
   extensions:        CPP
-  if impl(ghc)
-    extensions: OverloadedStrings
+  include-dirs:      include
 
 Test-Suite test-boxes
   type:              exitcode-stdio-1.0
   main-is:           Text/PrettyPrint/Tests.hs
   build-depends:     base >= 3 && < 5, split >=0.2 && <0.3, QuickCheck
   extensions:        CPP
-  if impl(ghc)
-     extensions: OverloadedStrings
+  include-dirs:      include
   cpp-options:       -DTESTING
+  other-modules:     Text.PrettyPrint.Boxes
 -- Export some internals so the tests can get at them
 
 source-repository head
   type: git
-  location: git://github.com/treeowl/boxes.git
+  location: https://github.com/treeowl/boxes.git
diff --git a/include/boxes.h b/include/boxes.h
new file mode 100644
--- /dev/null
+++ b/include/boxes.h
@@ -0,0 +1,40 @@
+/*
+ * Common macros for boxes
+ */
+
+#ifndef HASKELL_BOXES_H
+#define HASKELL_BOXES_H
+
+#ifdef __GLASGOW_HASKELL__ 
+#define OVERLOADED_STRINGS 1 
+#endif
+
+/*
+ * We use cabal-generated MIN_VERSION_base to adapt to changes of base.
+ * Nevertheless, as a convenience, we also allow compiling without cabal by
+ * defining an approximate MIN_VERSION_base if needed. The alternative version
+ * guesses the version of base using the version of GHC. This is usually
+ * sufficiently accurate. However, it completely ignores minor version numbers,
+ * and it makes the assumption that a pre-release version of GHC will ship with
+ * base libraries with the same version numbers as the final release. This
+ * assumption is violated in certain stages of GHC development, but in practice
+ * this should very rarely matter, and will not affect any released version.
+ */
+#ifndef MIN_VERSION_base
+#if __GLASGOW_HASKELL__ >= 709
+#define MIN_VERSION_base(major1,major2,minor) (((major1)<4)||(((major1) == 4)&&((major2)<=8)))
+#elif __GLASGOW_HASKELL__ >= 707
+#define MIN_VERSION_base(major1,major2,minor) (((major1)<4)||(((major1) == 4)&&((major2)<=7)))
+#elif __GLASGOW_HASKELL__ >= 705
+#define MIN_VERSION_base(major1,major2,minor) (((major1)<4)||(((major1) == 4)&&((major2)<=6)))
+#elif __GLASGOW_HASKELL__ >= 703
+#define MIN_VERSION_base(major1,major2,minor) (((major1)<4)||(((major1) == 4)&&((major2)<=5)))
+#elif __GLASGOW_HASKELL__ >= 701
+#define MIN_VERSION_base(major1,major2,minor) (((major1)<4)||(((major1) == 4)&&((major2)<=4)))
+#elif __GLASGOW_HASKELL__ >= 700
+#define MIN_VERSION_base(major1,major2,minor) (((major1)<4)||(((major1) == 4)&&((major2)<=3)))
+#else
+#define MIN_VERSION_base(major1,major2,minor) (0)
+#endif
+#endif /* ifndef MIN_VERSION_base */
+#endif /* ifndef HASKELL_BOXES_H */
