diff --git a/semigroups.cabal b/semigroups.cabal
--- a/semigroups.cabal
+++ b/semigroups.cabal
@@ -1,6 +1,6 @@
 name:          semigroups
 category:      Algebra, Data, Data Structures, Math
-version:       0.13.0.1
+version:       0.14
 license:       BSD3
 cabal-version: >= 1.10
 license-file:  LICENSE
@@ -20,40 +20,77 @@
   type: git
   location: git://github.com/ekmett/semigroups.git
 
-flag base2
-  default: False
-  manual: False
+flag hashable
+  description:
+    You can disable the use of the `hashable` package using `-f-hashable`.
+    .
+    Disabling this is an unsupported configuration, but it may be useful for accelerating builds in sandboxes for expert users.
+    .
+    If set we will not supply instances of `Hashable`
+    .
+    Note: `-f-hashable` implies `-f-unordered-containers`, as we are necessarily not able to supply those instances as well.
+  default: True
+  manual: True
 
+flag bytestring
+  description:
+    You can disable the use of the `bytestring` package using `-f-bytestring`.
+    .
+    Disabling this is an unsupported configuration, but it may be useful for accelerating builds in sandboxes for expert users.
+  default: True
+  manual: True
+
+flag containers
+  description:
+    You can disable the use of the `containers` package using `-f-containers`.
+    .
+    Disabing this is an unsupported configuration, but it may be useful for accelerating builds in sandboxes for expert users.
+  default: True
+  manual: True
+
+flag text
+  description:
+    You can disable the use of the `text` package using `-f-text`.
+    .
+    Disabling this is an unsupported configuration, but it may be useful for accelerating builds in sandboxes for expert users.
+  default: True
+  manual: True
+
+flag unordered-containers
+  description:
+    You can disable the use of the `unordered-containers` package using `-f-unordered-containers`.
+    .
+    Disabling this is an unsupported configuration, but it may be useful for accelerating builds in sandboxes for expert users.
+  default: True
+  manual: True
+
 library
   default-language: Haskell98
-  other-extensions: CPP
+  hs-source-dirs: src
+  ghc-options: -Wall
 
-  if !impl(hugs)
-    other-extensions: DeriveDataTypeable
-    cpp-options: -DLANGUAGE_DeriveDataTypeable
+  exposed-modules:
+    Data.Semigroup
+    Data.List.NonEmpty
 
+  build-depends:
+    base >= 2   && < 5,
+    nats >= 0.1 && < 1
+
   if impl(ghc >= 7.4 && < 7.5)
     build-depends: ghc-prim
 
-  if impl(ghc >= 7.4)
-    cpp-options: -DLANGUAGE_DeriveGeneric
+  if flag(bytestring)
+    build-depends: bytestring >= 0.9 && < 1
 
-  if flag(base2)
-    build-depends: base == 2.*
-    cpp-options: -DBASE2
-  else
-    build-depends:
-      base                 >= 3    && < 5,
-      bytestring           >= 0.9  && < 1,
-      containers           >= 0.3  && < 0.6,
-      hashable             >= 1.1  && < 1.3,
-      nats                 >= 0.1  && < 1,
-      text                 >= 0.10 && < 2,
-      unordered-containers >= 0.2  && < 0.3
+  if flag(containers)
+    build-depends: containers >= 0.3 && < 0.6
 
-  hs-source-dirs: src
-  ghc-options:    -Wall
+  if flag(text)
+    build-depends: text >= 0.10 && < 2
 
-  exposed-modules:
-    Data.Semigroup
-    Data.List.NonEmpty
+  if flag(hashable)
+    build-depends: hashable >= 1.1  && < 1.3
+
+  if flag(hashable) && flag(unordered-containers)
+    build-depends: unordered-containers >= 0.2  && < 0.3
diff --git a/src/Data/List/NonEmpty.hs b/src/Data/List/NonEmpty.hs
--- a/src/Data/List/NonEmpty.hs
+++ b/src/Data/List/NonEmpty.hs
@@ -1,7 +1,22 @@
 {-# LANGUAGE CPP #-}
-#ifdef LANGUAGE_DeriveDataTypeable
+
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 702
+#ifdef MIN_VERSION_hashable
+{-# LANGUAGE Trustworthy #-}
+#else
+{-# LANGUAGE Safe #-}
+#endif
+#endif
+
+#ifdef __GLASGOW_HASKELL__
+#define LANGUAGE_DeriveDataTypeable
 {-# LANGUAGE DeriveDataTypeable #-}
 #endif
+
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 704
+#define LANGUAGE_DeriveGeneric
+{-# LANGUAGE DeriveGeneric #-}
+#endif
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Data.List.NonEmpty
@@ -100,23 +115,27 @@
   , length
   )
 
-
 import Control.Applicative
--- import Control.Comonad
 import Control.Monad
--- import Data.Functor.Alt
+
+#ifdef LANGUAGE_DeriveDataTypeable
+import Data.Data
+#endif
+
 import Data.Foldable hiding (toList)
 import qualified Data.Foldable as Foldable
+
+#ifdef MIN_VERSION_hashable
+import Data.Hashable
+#endif
+
 import qualified Data.List as List
 import Data.Monoid (mappend)
 import Data.Ord (comparing)
 import Data.Traversable
--- import Data.Semigroup hiding (Last)
--- import Data.Semigroup.Foldable
--- import Data.Semigroup.Traversable
 
-#ifdef LANGUAGE_DeriveDataTypeable
-import Data.Data
+#ifdef LANGUAGE_DeriveGeneric
+import GHC.Generics
 #endif
 
 infixr 5 :|, <|
@@ -126,7 +145,19 @@
 #ifdef LANGUAGE_DeriveDataTypeable
   , Data, Typeable
 #endif
+#ifdef LANGUAGE_DeriveGeneric
+  , Generic
+#endif
   )
+
+#ifdef MIN_VERSION_hashable
+instance Hashable a => Hashable (NonEmpty a) where
+#if MIN_VERSION_hashable(1,2,0)
+  hashWithSalt p (a :| as) = p `hashWithSalt` a `hashWithSalt` as
+#else
+  hash (a :| as) = hash a `combine` hash as
+#endif
+#endif
 
 length :: NonEmpty a -> Int
 length (_ :| xs) = 1 + Prelude.length xs
diff --git a/src/Data/Semigroup.hs b/src/Data/Semigroup.hs
--- a/src/Data/Semigroup.hs
+++ b/src/Data/Semigroup.hs
@@ -1,15 +1,25 @@
 {-# LANGUAGE CPP #-}
-#ifdef LANGUAGE_DeriveDataTypeable
+
+#ifdef __GLASGOW_HASKELL__
+#define LANGUAGE_DeriveDataTypeable
 {-# LANGUAGE DeriveDataTypeable #-}
 #endif
-#ifdef LANGUAGE_DeriveGeneric
-{-# LANGUAGE DeriveGeneric #-}
-#endif
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+
 #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 702
+#define LANGUAGE_DefaultSignatures
 {-# LANGUAGE DefaultSignatures #-}
+#ifdef MIN_VERSION_hashable
 {-# LANGUAGE Trustworthy #-}
+#else
+{-# LANGUAGE Safe #-}
 #endif
+#endif
+
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 704
+#define LANGUAGE_DeriveGeneric
+{-# LANGUAGE DeriveGeneric #-}
+#endif
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Data.Semigroup
@@ -69,20 +79,31 @@
 import Data.Foldable
 import Data.Traversable
 import Data.List.NonEmpty
-
 import Numeric.Natural.Internal
+
+#ifdef MIN_VERSION_containers
 import Data.Sequence (Seq, (><))
 import Data.Set (Set)
 import Data.IntSet (IntSet)
 import Data.Map (Map)
 import Data.IntMap (IntMap)
+#endif
 
-#ifndef BASE2
+#ifdef MIN_VERSION_bytestring
 import Data.ByteString as Strict
 import Data.ByteString.Lazy as Lazy
+#endif
+
+#ifdef MIN_VERSION_text
 import qualified Data.Text as Strict
 import qualified Data.Text.Lazy as Lazy
+#endif
+
+#ifdef MIN_VERSION_hashable
 import Data.Hashable
+#endif
+
+#ifdef MIN_VERSION_unordered_containers
 import Data.HashMap.Lazy as Lazy
 import Data.HashSet
 #endif
@@ -90,6 +111,7 @@
 #ifdef LANGUAGE_DeriveDataTypeable
 import Data.Data
 #endif
+
 #ifdef LANGUAGE_DeriveGeneric
 import GHC.Generics
 #endif
@@ -109,7 +131,7 @@
   -- ('<>') = 'mappend'
   -- @
   (<>) :: a -> a -> a
-#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 702
+#ifdef LANGUAGE_DefaultSignatures
   default (<>) :: Monoid a => a -> a -> a
   (<>) = mappend
 #endif
@@ -237,13 +259,38 @@
   (a :| as) <> ~(b :| bs) = a :| (as ++ b : bs)
 
 newtype Min a = Min { getMin :: a } deriving
-  ( Eq, Ord, Enum, Bounded, Show, Read
-  , Hashable
+  ( Eq, Ord, Show, Read
 #ifdef LANGUAGE_DeriveDataTypeable
   , Data, Typeable
 #endif
+#ifdef LANGUAGE_DeriveGeneric
+  , Generic
+#endif
   )
 
+instance Bounded a => Bounded (Min a) where
+  minBound = Min minBound
+  maxBound = Min maxBound
+
+instance Enum a => Enum (Min a) where
+  succ (Min a) = Min (succ a)
+  pred (Min a) = Min (succ a)
+  toEnum = Min . toEnum
+  fromEnum = fromEnum . getMin
+  enumFrom (Min a) = Min <$> enumFrom a
+  enumFromThen (Min a) (Min b) = Min <$> enumFromThen a b
+  enumFromTo (Min a) (Min b) = Min <$> enumFromTo a b
+  enumFromThenTo (Min a) (Min b) (Min c) = Min <$> enumFromThenTo a b c
+
+#ifdef MIN_VERSION_hashable
+instance Hashable a => Hashable (Min a) where
+#if MIN_VERSION_hashable(1,2,0)
+  hashWithSalt p (Min a) = hashWithSalt p a
+#else
+  hash (Min a) = hash a
+#endif
+#endif
+
 instance Ord a => Semigroup (Min a) where
   Min a <> Min b = Min (a `min` b)
   times1p _ a = a
@@ -276,8 +323,7 @@
   mfix f = fix (f . getMin)
 
 newtype Max a = Max { getMax :: a } deriving
-  ( Eq, Ord, Enum, Bounded, Show, Read
-  , Hashable
+  ( Eq, Ord, Show, Read
 #ifdef LANGUAGE_DeriveDataTypeable
   , Data, Typeable
 #endif
@@ -286,6 +332,29 @@
 #endif
   )
 
+instance Bounded a => Bounded (Max a) where
+  minBound = Max minBound
+  maxBound = Max maxBound
+
+instance Enum a => Enum (Max a) where
+  succ (Max a) = Max (succ a)
+  pred (Max a) = Max (succ a)
+  toEnum = Max . toEnum
+  fromEnum = fromEnum . getMax
+  enumFrom (Max a) = Max <$> enumFrom a
+  enumFromThen (Max a) (Max b) = Max <$> enumFromThen a b
+  enumFromTo (Max a) (Max b) = Max <$> enumFromTo a b
+  enumFromThenTo (Max a) (Max b) (Max c) = Max <$> enumFromThenTo a b c
+
+#ifdef MIN_VERSION_hashable
+instance Hashable a => Hashable (Max a) where
+#if MIN_VERSION_hashable(1,2,0)
+  hashWithSalt p (Max a) = hashWithSalt p a
+#else
+  hash (Max a) = hash a
+#endif
+#endif
+
 instance Ord a => Semigroup (Max a) where
   Max a <> Max b = Max (a `max` b)
   times1p _ a = a
@@ -319,8 +388,7 @@
 
 -- | Use @'Option' ('First' a)@ to get the behavior of 'Data.Monoid.First' from @Data.Monoid@.
 newtype First a = First { getFirst :: a } deriving
-  ( Eq, Ord, Enum, Bounded, Show, Read
-  , Hashable
+  ( Eq, Ord, Show, Read
 #ifdef LANGUAGE_DeriveDataTypeable
   , Data
   , Typeable
@@ -330,6 +398,29 @@
 #endif
   )
 
+instance Bounded a => Bounded (First a) where
+  minBound = First minBound
+  maxBound = First maxBound
+
+instance Enum a => Enum (First a) where
+  succ (First a) = First (succ a)
+  pred (First a) = First (succ a)
+  toEnum = First . toEnum
+  fromEnum = fromEnum . getFirst
+  enumFrom (First a) = First <$> enumFrom a
+  enumFromThen (First a) (First b) = First <$> enumFromThen a b
+  enumFromTo (First a) (First b) = First <$> enumFromTo a b
+  enumFromThenTo (First a) (First b) (First c) = First <$> enumFromThenTo a b c
+
+#ifdef MIN_VERSION_hashable
+instance Hashable a => Hashable (First a) where
+#if MIN_VERSION_hashable(1,2,0)
+  hashWithSalt p (First a) = hashWithSalt p a
+#else
+  hash (First a) = hash a
+#endif
+#endif
+
 instance Semigroup (First a) where
   a <> _ = a
   times1p _ a = a
@@ -359,8 +450,7 @@
 
 -- | Use @'Option' ('Last' a)@ to get the behavior of 'Data.Monoid.Last' from @Data.Monoid@
 newtype Last a = Last { getLast :: a } deriving
-  ( Eq, Ord, Enum, Bounded, Show, Read
-  , Hashable
+  ( Eq, Ord, Show, Read
 #ifdef LANGUAGE_DeriveDataTypeable
   , Data, Typeable
 #endif
@@ -369,6 +459,29 @@
 #endif
   )
 
+instance Bounded a => Bounded (Last a) where
+  minBound = Last minBound
+  maxBound = Last maxBound
+
+instance Enum a => Enum (Last a) where
+  succ (Last a) = Last (succ a)
+  pred (Last a) = Last (succ a)
+  toEnum = Last . toEnum
+  fromEnum = fromEnum . getLast
+  enumFrom (Last a) = Last <$> enumFrom a
+  enumFromThen (Last a) (Last b) = Last <$> enumFromThen a b
+  enumFromTo (Last a) (Last b) = Last <$> enumFromTo a b
+  enumFromThenTo (Last a) (Last b) (Last c) = Last <$> enumFromThenTo a b c
+
+#ifdef MIN_VERSION_hashable
+instance Hashable a => Hashable (Last a) where
+#if MIN_VERSION_hashable(1,2,0)
+  hashWithSalt p (Last a) = hashWithSalt p a
+#else
+  hash (Last a) = hash a
+#endif
+#endif
+
 instance Semigroup (Last a) where
   _ <> b = b
   times1p _ a = a
@@ -399,19 +512,23 @@
 
 -- (==)/XNOR on Bool forms a 'Semigroup', but has no good name
 
-#ifndef BASE2
+#ifdef MIN_VERSION_bytestring
 instance Semigroup Strict.ByteString where
   (<>) = mappend
 
 instance Semigroup Lazy.ByteString where
   (<>) = mappend
+#endif
 
+#ifdef MIN_VERSION_text
 instance Semigroup Strict.Text where
   (<>) = mappend
 
 instance Semigroup Lazy.Text where
   (<>) = mappend
+#endif
 
+#ifdef MIN_VERSION_unordered_containers
 instance (Hashable k, Eq k) => Semigroup (Lazy.HashMap k a) where
   (<>) = mappend
 
@@ -423,8 +540,7 @@
 -- | Provide a Semigroup for an arbitrary Monoid.
 newtype WrappedMonoid m = WrapMonoid
   { unwrapMonoid :: m } deriving
-  ( Eq, Ord, Enum, Bounded, Show, Read
-  , Hashable
+  ( Eq, Ord, Show, Read
 #ifdef LANGUAGE_DeriveDataTypeable
   , Data, Typeable
 #endif
@@ -433,6 +549,15 @@
 #endif
   )
 
+#ifdef MIN_VERSION_hashable
+instance Hashable a => Hashable (WrappedMonoid a) where
+#if MIN_VERSION_hashable(1,2,0)
+  hashWithSalt p (WrapMonoid a) = hashWithSalt p a
+#else
+  hash (WrapMonoid a) = hash a
+#endif
+#endif
+
 instance Monoid m => Semigroup (WrappedMonoid m) where
   WrapMonoid a <> WrapMonoid b = WrapMonoid (a `mappend` b)
 
@@ -440,6 +565,20 @@
   mempty = WrapMonoid mempty
   WrapMonoid a `mappend` WrapMonoid b = WrapMonoid (a `mappend` b)
 
+instance Bounded a => Bounded (WrappedMonoid a) where
+  minBound = WrapMonoid minBound
+  maxBound = WrapMonoid maxBound
+
+instance Enum a => Enum (WrappedMonoid a) where
+  succ (WrapMonoid a) = WrapMonoid (succ a)
+  pred (WrapMonoid a) = WrapMonoid (succ a)
+  toEnum = WrapMonoid . toEnum
+  fromEnum = fromEnum . unwrapMonoid
+  enumFrom (WrapMonoid a) = WrapMonoid <$> enumFrom a
+  enumFromThen (WrapMonoid a) (WrapMonoid b) = WrapMonoid <$> enumFromThen a b
+  enumFromTo (WrapMonoid a) (WrapMonoid b) = WrapMonoid <$> enumFromTo a b
+  enumFromThenTo (WrapMonoid a) (WrapMonoid b) (WrapMonoid c) = WrapMonoid <$> enumFromThenTo a b c
+
 -- | Repeat a value @n@ times.
 --
 -- > timesN n a = a <> a <> ... <> a  -- using <> (n-1) times
@@ -458,7 +597,6 @@
 newtype Option a = Option
   { getOption :: Maybe a } deriving
   ( Eq, Ord, Show, Read
-  , Hashable
 #ifdef LANGUAGE_DeriveDataTypeable
   , Data, Typeable
 #endif
@@ -467,6 +605,15 @@
 #endif
   )
 
+#ifdef MIN_VERSION_hashable
+instance Hashable a => Hashable (Option a) where
+#if MIN_VERSION_hashable(1,2,0)
+  hashWithSalt p (Option a) = hashWithSalt p a
+#else
+  hash (Option a) = hash a
+#endif
+#endif
+
 instance Functor Option where
   fmap f (Option a) = Option (fmap f a)
 
@@ -518,6 +665,7 @@
 diff :: Semigroup m => m -> Endo m
 diff = Endo . (<>)
 
+#ifdef MIN_VERSION_containers
 instance Semigroup (Seq a) where
   (<>) = (><)
 
@@ -536,3 +684,4 @@
 instance Ord k => Semigroup (Map k v) where
   (<>) = mappend
   times1p _ a = a
+#endif
