diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,31 @@
+Copyright (c) 2006-2009 Don Stewart, 2013-2016 Sean Leather, 2017 Oleg Grenrus
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Don Stewart nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,33 @@
+# Difference Lists in Haskell
+
+The `NonEmpty` version of difference lists: list-like type supporting O(1) append ans snoc operations.
+
+This is a fork of a [`dlist`](http://hackage.haskell.org/package/dlist) package.
+
+```
+benchmarking append 1000/List
+time                 27.66 ms   (27.30 ms .. 28.01 ms)
+                     0.999 R²   (0.999 R² .. 1.000 R²)
+mean                 28.39 ms   (28.21 ms .. 28.58 ms)
+std dev              391.5 μs   (311.7 μs .. 510.3 μs)
+
+benchmarking append 1000/NonEmpty
+time                 33.67 ms   (33.01 ms .. 34.27 ms)
+                     0.999 R²   (0.999 R² .. 1.000 R²)
+mean                 34.07 ms   (33.90 ms .. 34.29 ms)
+std dev              419.3 μs   (308.9 μs .. 549.3 μs)
+
+benchmarking append 1000/DList
+time                 57.46 μs   (56.95 μs .. 58.12 μs)
+                     0.999 R²   (0.998 R² .. 0.999 R²)
+mean                 57.98 μs   (57.61 μs .. 58.41 μs)
+std dev              1.398 μs   (1.115 μs .. 1.871 μs)
+variance introduced by outliers: 22% (moderately inflated)
+
+benchmarking append 1000/NonEmptyDList
+time                 90.37 μs   (89.09 μs .. 91.44 μs)
+                     0.999 R²   (0.998 R² .. 0.999 R²)
+mean                 89.31 μs   (88.61 μs .. 89.96 μs)
+std dev              2.244 μs   (1.763 μs .. 2.988 μs)
+variance introduced by outliers: 22% (moderately inflated)
+```
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/bench/Main.hs b/bench/Main.hs
new file mode 100644
--- /dev/null
+++ b/bench/Main.hs
@@ -0,0 +1,29 @@
+import Criterion.Main
+
+import Prelude ()
+import Prelude.Compat
+
+import Data.List (foldl')
+import Data.Foldable (toList)
+import Data.Semigroup (Semigroup (..))
+import Data.DList.Instances ()
+
+import qualified Data.List.NonEmpty as NE
+import qualified Data.DList as DList
+import qualified Data.DList.NonEmpty as NEDList
+
+sum' :: (Semigroup (f Int), Foldable f) => Int -> f Int -> Int
+sum' m x = foldl' (+) 0 $ toList $ go x m
+  where
+    go y n | n <= 0    = y
+           | otherwise = go (y <> x) (n - 1)
+
+main :: IO ()
+main = defaultMain
+    [ bgroup "append 1000"
+        [ bench "List"          $ whnf (sum' 1000) $ [1,2,3,4,5]
+        , bench "NonEmpty"      $ whnf (sum' 1000) $ 1 NE.:| [2,3,4,5]
+        , bench "DList"         $ whnf (sum' 1000) $ DList.fromList [1,2,3,4,5]
+        , bench "NonEmptyDList" $ whnf (sum' 1000) $ NEDList.fromNonEmpty $ 1 NE.:| [2,3,4,5]
+        ]
+    ]
diff --git a/dlist-nonempty.cabal b/dlist-nonempty.cabal
new file mode 100644
--- /dev/null
+++ b/dlist-nonempty.cabal
@@ -0,0 +1,84 @@
+name:                   dlist-nonempty
+version:                0.1
+synopsis:               Non-empty difference lists
+description:
+  Difference lists are a list-like type supporting O(1) append. This is
+  particularly useful for efficient logging and pretty printing (e.g. with the
+  Writer monad), where list append quickly becomes too expensive.
+  .
+  > DList a         ≅ [a] -> [a]
+  > NonEmptyDList a ≅ [a] -> NonEmpty a
+  .
+  For empty variant, @DList@, see <http://hackage.haskell.org/package/dlist dlist package>.
+category:               Data
+license:                BSD3
+license-file:           LICENSE
+author:                 Don Stewart, Oleg  Grenrus
+maintainer:             Oleg Grenrus <oleg.grenrus@iki.fi>
+copyright:              2006-2009 Don Stewart, 2013-2016 Sean Leather, 2017 Oleg Grenrus
+homepage:               https://github.com/phadej/dlist-nonempty
+bug-reports:            https://github.com/phadej/dlist-nonempty/issues
+extra-source-files:     README.md
+build-type:             Simple
+cabal-version:          >=1.10
+tested-with:
+  GHC==7.4.2,
+  GHC==7.6.3,
+  GHC==7.8.4,
+  GHC==7.10.3,
+  GHC==8.0.2,
+  GHC==8.2.1
+
+source-repository head
+  type:                 git
+  location:             git://github.com/phadej/dlist-nonempty.git
+
+library
+  default-language:     Haskell2010
+  hs-source-dirs:       src
+  build-depends:
+                        base          >=4.5   && <4.11,
+                        base-compat   >=0.9.1 && <0.10,
+                        deepseq       >=1.1   && <2,
+                        dlist         >=0.8   && <0.9,
+                        semigroupoids >=5.1   && <5.3
+  if !impl(ghc >= 8.0)
+    build-depends:
+                        semigroups >=0.18.2 && <0.19
+  other-extensions:     CPP
+  exposed-modules:      Data.DList.NonEmpty
+                        Data.DList.NonEmpty.Unsafe
+  other-modules:        Data.DList.NonEmpty.Internal
+  ghc-options:          -Wall
+  if impl(ghc >= 8.0)
+    ghc-options:        -Wcompat
+
+test-suite test
+  default-language:     Haskell2010
+  type:                 exitcode-stdio-1.0
+  main-is:              Main.hs
+  hs-source-dirs:       tests
+  other-modules:        OverloadedStrings
+  build-depends:        dlist-nonempty,
+                        base,
+                        Cabal,
+                        QuickCheck >= 2.9 && < 2.11,
+                        quickcheck-instances
+  if !impl(ghc >= 8.0)
+    build-depends:
+                        semigroups >=0.18.2 && <0.19
+
+benchmark bench
+  default-language:     Haskell2010
+  type:                 exitcode-stdio-1.0
+  main-is:              Main.hs
+  hs-source-dirs:       bench
+  build-depends:        base,
+                        base-compat,
+                        dlist,
+                        dlist-nonempty,
+                        dlist-instances,
+                        criterion >= 1.1.4.0 && <1.3
+  if !impl(ghc >= 8.0)
+    build-depends:
+                        semigroups >=0.18.2 && <0.19
diff --git a/src/Data/DList/NonEmpty.hs b/src/Data/DList/NonEmpty.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/DList/NonEmpty.hs
@@ -0,0 +1,47 @@
+{-# LANGUAGE CPP #-}
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708
+{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
+#endif
+
+-- | Non-empty difference lists: a data structure for /O(1)/ append on non-empty lists.
+module Data.DList.NonEmpty
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 800
+  ( NonEmptyDList(Cons)
+#else
+  ( NonEmptyDList
+#endif
+
+  -- * Conversion
+  , toNonEmpty
+  , apply
+  , toList
+  , toDList
+  , toEndo
+  , toEndo'
+
+  -- * Construction
+  --
+  -- | The O(1) functions.
+  , fromNonEmpty
+  , singleton
+  , cons
+  , snoc
+  , append
+
+  -- * Other functions
+  , concat1
+  , replicate
+  , head
+  , tail
+  , unfoldr
+  , map
+
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708 && __GLASGOW_HASKELL__ < 800
+  -- * Pattern Synonyms
+  , pattern Cons
+#endif
+
+  ) where
+
+import Prelude ()
+import Data.DList.NonEmpty.Internal
diff --git a/src/Data/DList/NonEmpty/Internal.hs b/src/Data/DList/NonEmpty/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/DList/NonEmpty/Internal.hs
@@ -0,0 +1,268 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE TypeFamilies #-} -- For the IsList (uses family) and IsString (~) instances
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708
+{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
+#endif
+
+-- | Non-empty difference lists: a data structure for /O(1)/ append on non-empty lists.
+module Data.DList.NonEmpty.Internal where
+
+import Prelude ()
+import Prelude.Compat hiding (concat, foldr, map, head, tail, replicate)
+
+import Control.DeepSeq (NFData (..))
+import Control.Monad
+import Data.Function (on)
+import Data.List.NonEmpty (NonEmpty (..))
+import Data.Monoid (Endo (..))
+import Data.Semigroup (Semigroup(..))
+import Data.String (IsString(..))
+
+import qualified Data.List as List
+import qualified Data.List.NonEmpty as NE
+import qualified Data.Foldable as F
+import qualified Data.DList as DList
+
+-- semigroupoids
+import Data.Functor.Apply (Apply (..))
+import Data.Functor.Bind (Bind (..))
+import Data.Functor.Alt (Alt (..))
+import Data.Semigroup.Foldable (Foldable1 (..))
+import Data.Semigroup.Traversable (Traversable1 (..))
+
+#ifdef __GLASGOW_HASKELL__
+
+import Text.Read (Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec,
+                  readListPrecDefault)
+
+#if __GLASGOW_HASKELL__ >= 708
+import GHC.Exts (IsList)
+-- This is for the IsList methods, which conflict with fromList, toList:
+import qualified GHC.Exts
+#endif
+
+#endif
+
+-- | A difference list is a function that, given a list, returns the original
+-- contents of the difference list prepended to the given list.
+--
+-- Implemented as a newtype over @[a] -> 'NonEmpty' a@.
+newtype NonEmptyDList a = NEDL { unNEDL :: [a] -> NonEmpty a }
+
+-- | Convert a list to a dlist
+fromNonEmpty :: NonEmpty a -> NonEmptyDList a
+fromNonEmpty (x :| xs) = NEDL $ (x :|) . (xs ++)
+{-# INLINE fromNonEmpty #-}
+
+-- | Convert a dlist to a non-empty list
+toNonEmpty :: NonEmptyDList a -> NonEmpty a
+toNonEmpty = ($[]) . unNEDL
+{-# INLINE toNonEmpty #-}
+
+-- | Convert a dlist to a list
+toList :: NonEmptyDList a -> [a]
+toList = NE.toList . toNonEmpty
+{-# INLINE toList #-}
+
+-- | Convert to 'DList'.
+--
+-- /Note:/ @dlist@ doesn't expose internals, so this have to go through list.
+toDList :: NonEmptyDList a -> DList.DList a
+toDList = DList.fromList . toList
+{-# INLINE toDList #-}
+
+-- | Convert to representation of 'DList'.
+toEndo :: NonEmptyDList a -> Endo [a]
+toEndo ne = Endo (NE.toList . unNEDL ne)
+
+-- | Convert to representation of 'DList'.
+toEndo' :: NonEmptyDList a -> [a] -> [a]
+toEndo' = appEndo . toEndo
+
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708
+-- | A unidirectional pattern synonym using 'toList' in a view pattern and
+-- matching on @x:xs@ such that you have the pattern @Cons x xs@
+#if __GLASGOW_HASKELL__ >= 710
+pattern Cons :: a -> [a] -> NonEmptyDList a
+#endif
+pattern Cons x xs <- (toNonEmpty -> x :| xs)
+#endif
+
+-- | Apply a dlist to a list to get the underlying non-empty list with an extension
+apply :: NonEmptyDList a -> [a] -> NonEmpty a
+apply = unNEDL
+
+-- | Create dlist with a single element
+singleton :: a -> NonEmptyDList a
+singleton = NEDL . (:|)
+{-# INLINE singleton #-}
+
+-- | /O(1)/. Prepend a single element to a dlist
+infixr `cons`
+cons :: a -> NonEmptyDList a -> NonEmptyDList a
+cons x xs = NEDL (NE.cons x . unNEDL xs)
+{-# INLINE cons #-}
+
+-- | /O(1)/. Append a single element to a dlist
+infixl `snoc`
+snoc :: NonEmptyDList a -> a -> NonEmptyDList a
+snoc xs x = NEDL (unNEDL xs . (x:))
+{-# INLINE snoc #-}
+
+-- | /O(1)/. Append dlists
+append :: NonEmptyDList a -> NonEmptyDList a -> NonEmptyDList a
+append xs ys = NEDL (unNEDL xs . NE.toList . unNEDL ys)
+{-# INLINE append #-}
+
+-- | /O(spine)/. Concatenate dlists
+concat1 :: NonEmpty (NonEmptyDList a) -> NonEmptyDList a
+concat1 = sconcat
+{-# INLINE concat1 #-}
+
+-- | /O(n)/. Create a dlist of the given number of elements.
+--
+-- Always creates a list with at least one element.
+replicate :: Int -> a -> NonEmptyDList a
+replicate n x = NEDL $ \xs -> let go m | m <= 1 = x :| xs
+                                     | otherwise = NE.cons x $ go (m-1)
+                            in go n
+{-# INLINE replicate #-}
+
+-- | /O(n)/. Return the head of the dlist
+head :: NonEmptyDList a -> a
+head = NE.head . toNonEmpty
+
+-- | /O(n)/. Return the tail of the dlist
+tail :: NonEmptyDList a -> [a]
+tail = NE.tail . toNonEmpty
+
+-- | /O(n)/. Unfoldr for dlists
+unfoldr :: (b -> (a, Maybe b)) -> b -> NonEmptyDList a
+unfoldr pf b = case pf b of
+    (a, Nothing) -> singleton a
+    (a, Just b')  -> cons a (unfoldr pf b')
+
+-- | /O(n)/. Map over difference lists.
+map :: (a -> b) -> NonEmptyDList a -> NonEmptyDList b
+map f = fromNonEmpty . fmap f . toNonEmpty
+{-# INLINE map #-}
+
+instance Eq a => Eq (NonEmptyDList a) where
+  (==) = (==) `on` toList
+
+instance Ord a => Ord (NonEmptyDList a) where
+  compare = compare `on` toList
+
+-- The Read and Show instances were adapted from Data.Sequence.
+
+instance Read a => Read (NonEmptyDList a) where
+#ifdef __GLASGOW_HASKELL__
+  readPrec = parens $ prec 10 $ do
+    Ident "fromNonEmpty" <- lexP
+    dl <- readPrec
+    return (fromNonEmpty dl)
+  readListPrec = readListPrecDefault
+#else
+  readsPrec p = readParen (p > 10) $ \r -> do
+    ("fromNonEmpty", s) <- lex r
+    (dl, t) <- readsPrec 11 s
+    return (fromNonEmpty dl, t)
+#endif
+
+instance Show a => Show (NonEmptyDList a) where
+  showsPrec p dl = showParen (p > 10) $
+    showString "fromNonEmpty " . showsPrec 11 (toNonEmpty dl)
+
+instance Functor NonEmptyDList where
+  fmap = map
+  {-# INLINE fmap #-}
+
+instance Applicative NonEmptyDList where
+  pure = singleton
+  {-# INLINE pure #-}
+  (<*>) = ap
+
+instance Monad NonEmptyDList where
+  m >>= k
+    -- = concat (toList (fmap k m))
+    -- = (concat . toList . fromList . List.map k . toList) m
+    -- = concat . List.map k . toList $ m
+    -- = List.foldr append empty . List.map k . toList $ m
+    -- = List.foldr (append . k) empty . toList $ m
+   = concat1 . fmap k . toNonEmpty $ m
+  {-# INLINE (>>=) #-}
+
+  return = pure
+  {-# INLINE return #-}
+
+instance Foldable NonEmptyDList where
+  fold = mconcat . toList
+  {-# INLINE fold #-}
+
+  foldMap f = F.foldMap f . toList
+  {-# INLINE foldMap #-}
+
+  foldr f x = List.foldr f x . toList
+  {-# INLINE foldr #-}
+
+  foldl f x = List.foldl f x . toList
+  {-# INLINE foldl #-}
+
+  foldr1 f = List.foldr1 f . toList
+  {-# INLINE foldr1 #-}
+
+  foldl1 f = List.foldl1 f . toList
+  {-# INLINE foldl1 #-}
+
+-- CPP: foldl', foldr' added to Foldable in 7.6.1
+-- http://www.haskell.org/ghc/docs/7.6.1/html/users_guide/release-7-6-1.html
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 706
+  foldl' f x = List.foldl' f x . toList
+  {-# INLINE foldl' #-}
+
+  foldr' f x = F.foldr' f x . toList
+  {-# INLINE foldr' #-}
+#endif
+
+instance Traversable NonEmptyDList where
+  traverse f = fmap fromNonEmpty . traverse f . toNonEmpty
+  sequenceA  = fmap fromNonEmpty . sequenceA . toNonEmpty
+
+instance NFData a => NFData (NonEmptyDList a) where
+  rnf = rnf . toNonEmpty
+  {-# INLINE rnf #-}
+
+-- This is partial instance. Will fail on empty string.
+instance a ~ Char => IsString (NonEmptyDList a) where
+  fromString = fromNonEmpty . NE.fromList
+  {-# INLINE fromString #-}
+
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708
+instance IsList (NonEmptyDList a) where
+  type Item (NonEmptyDList a) = a
+  fromList = fromNonEmpty . NE.fromList
+  {-# INLINE fromList #-}
+  toList = toList
+  {-# INLINE toList #-}
+#endif
+
+instance Semigroup (NonEmptyDList a) where
+  (<>) = append
+  {-# INLINE (<>) #-}
+
+-------------------------------------------------------------------------------
+-- semigroupoids
+-------------------------------------------------------------------------------
+
+instance Apply NonEmptyDList where (<.>) = (<*>)
+instance Bind NonEmptyDList where (>>-) = (>>=)
+
+instance Foldable1 NonEmptyDList where
+  foldMap1 f = foldMap1 f . toNonEmpty
+
+instance Traversable1 NonEmptyDList where
+  traverse1 f = fmap fromNonEmpty . traverse1 f . toNonEmpty
+  sequence1   = fmap fromNonEmpty . sequence1 . toNonEmpty
+
+instance Alt NonEmptyDList where
+  (<!>) = append
diff --git a/src/Data/DList/NonEmpty/Unsafe.hs b/src/Data/DList/NonEmpty/Unsafe.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/DList/NonEmpty/Unsafe.hs
@@ -0,0 +1,11 @@
+-- | This module exports the internal representation of 'NonEmptyDList'.
+--
+-- Use with care. It's very easy to break the safe interface:
+--
+-- >>> let nedl = NEDL ((1 :|) . map (+1))
+-- >>> nedl <> nedl
+-- fromNonEmpty (1 :| [2])
+--
+module Data.DList.NonEmpty.Unsafe (NonEmptyDList (..)) where
+
+import Data.DList.NonEmpty.Internal
diff --git a/tests/Main.hs b/tests/Main.hs
new file mode 100644
--- /dev/null
+++ b/tests/Main.hs
@@ -0,0 +1,150 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE CPP #-}
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708
+{-# LANGUAGE OverloadedLists #-} -- For the IsList test
+#if __GLASGOW_HASKELL__ == 708
+{-# LANGUAGE PatternSynonyms #-} -- For pattern synonym use only in GHC 7.8
+#endif
+#endif
+
+
+--------------------------------------------------------------------------------
+
+module Main (main) where
+
+--------------------------------------------------------------------------------
+
+import Prelude hiding (concat, foldr, head, map, replicate, tail)
+import qualified Data.List as List
+import Test.QuickCheck
+import Test.QuickCheck.Instances ()
+import Test.QuickCheck.Function
+
+import Data.DList.NonEmpty
+
+import OverloadedStrings (testOverloadedStrings)
+
+import Data.Semigroup (Semigroup(..))
+import Data.List.NonEmpty (NonEmpty(..))
+import qualified Data.List.NonEmpty as NE
+
+--------------------------------------------------------------------------------
+
+eqWith :: (Eq b, Show b) => (a -> b) -> (a -> b) -> a -> Property
+eqWith f g x = f x === g x
+
+eqOn :: (Eq b, Show b) => (a -> Bool) -> (a -> b) -> (a -> b) -> a -> Property
+eqOn c f g x = c x ==> f x === g x
+
+--------------------------------------------------------------------------------
+
+prop_model :: NonEmpty Int -> Property
+prop_model = eqWith id (toNonEmpty . fromNonEmpty)
+
+prop_singleton :: Int -> Property
+prop_singleton = eqWith (:|[]) (toNonEmpty . singleton)
+
+prop_cons :: Int -> NonEmpty Int -> Property
+prop_cons c = eqWith (NE.cons c) (toNonEmpty . cons c . fromNonEmpty)
+
+prop_snoc :: NonEmpty Int -> Int -> Property
+prop_snoc xs c = xs <> (c :| []) === toNonEmpty (snoc (fromNonEmpty xs) c)
+
+prop_append :: NonEmpty Int -> NonEmpty Int -> Property
+prop_append xs ys = xs <> ys === toNonEmpty (fromNonEmpty xs `append` fromNonEmpty ys)
+
+prop_concat1 :: NonEmpty (NonEmpty Int) -> Property
+prop_concat1 = eqWith sconcat (toNonEmpty . concat1 . fmap fromNonEmpty)
+
+-- The condition reduces the size of replications and thus the eval time.
+prop_replicate :: Int -> Int -> Property
+prop_replicate n =
+  eqOn (const (n < 100)) (rep n) (toNonEmpty . replicate n)
+  where
+    rep m x = x :| List.replicate (m - 1) x
+
+prop_head :: NonEmpty Int -> Property
+prop_head = eqWith NE.head (head . fromNonEmpty)
+
+prop_tail :: NonEmpty Int -> Property
+prop_tail = eqWith NE.tail (tail . fromNonEmpty)
+
+prop_unfoldr :: Fun Int (Int, Maybe Int) -> Int -> Int -> Property
+prop_unfoldr (Fun _ f) n =
+  eqOn (const (n >= 0)) (NE.take n . NE.unfoldr f) (NE.take n . toNonEmpty . unfoldr f)
+
+prop_map :: Fun Int Int -> NonEmpty Int -> Property
+prop_map (Fun _ f) = eqWith (fmap f) (toNonEmpty . map f . fromNonEmpty)
+
+prop_map_fusion :: (Int -> Int) -> (a -> Int) -> NonEmpty a -> Property
+prop_map_fusion f g =
+  eqWith (fmap f . fmap g) (toNonEmpty . map f . map g . fromNonEmpty)
+
+prop_show_read :: [Int] -> Property
+prop_show_read = eqWith id (read . show)
+
+prop_read_show :: NonEmpty Int -> Property
+prop_read_show x = eqWith id (show . f . read) $ "fromNonEmpty (" <> show x <> ")"
+  where
+    f :: NonEmptyDList Int -> NonEmptyDList Int
+    f = id
+
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708
+-- | Test that the IsList instance methods compile and work with simple lists
+prop_IsList :: Property
+prop_IsList = test_fromNonEmpty [1,2,3] .&&. test_toNonEmpty (fromNonEmpty [1,2,3])
+  where
+    test_fromNonEmpty, test_toNonEmpty :: NonEmptyDList Int -> Property
+    test_fromNonEmpty x = x === fromNonEmpty [1,2,3]
+    test_toNonEmpty [1,2,3] = property True
+    test_toNonEmpty _       = property False
+
+prop_patterns :: NonEmpty Int -> Property
+prop_patterns xs = case fromNonEmpty xs of
+  Cons y ys -> xs === (y:|ys)
+  _         -> property False
+#endif
+
+prop_Semigroup_append :: NonEmpty Int -> NonEmpty Int -> Property
+prop_Semigroup_append xs ys = xs <> ys === toNonEmpty (fromNonEmpty xs <> fromNonEmpty ys)
+
+prop_Semigroup_sconcat :: NonEmpty (NonEmpty Int) -> Property
+prop_Semigroup_sconcat xs = sconcat xs === toNonEmpty (sconcat (fmap fromNonEmpty xs))
+
+prop_Semigroup_stimes :: Int -> NonEmpty Int -> Property
+prop_Semigroup_stimes n xs = n >=1 ==>
+    stimes n xs === toNonEmpty (stimes n (fromNonEmpty xs))
+
+--------------------------------------------------------------------------------
+
+props :: [(String, Property)]
+props =
+  [ ("model",             property prop_model)
+  , ("singleton",         property prop_singleton)
+  , ("cons",              property prop_cons)
+  , ("snoc",              property prop_snoc)
+  , ("append",            property prop_append)
+  , ("concat1",           property prop_concat1)
+  , ("replicate",         property prop_replicate)
+  , ("head",              property prop_head)
+  , ("tail",              property prop_tail)
+  , ("unfoldr",           property prop_unfoldr)
+  , ("map",               property prop_map)
+  , ("map fusion",        property (prop_map_fusion (+1) (+1)))
+  , ("read . show",       property prop_show_read)
+  , ("show . read",       property prop_read_show)
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708
+  , ("IsList",            property prop_IsList)
+  , ("patterns",          property prop_patterns)
+#endif
+  , ("Semigroup <>",      property prop_Semigroup_append)
+  , ("Semigroup sconcat", property prop_Semigroup_sconcat)
+  , ("Semigroup stimes",  property prop_Semigroup_stimes)
+  ]
+
+--------------------------------------------------------------------------------
+
+main :: IO ()
+main = do
+  testOverloadedStrings
+  quickCheck $ conjoin $ fmap (uncurry label) props
diff --git a/tests/OverloadedStrings.hs b/tests/OverloadedStrings.hs
new file mode 100644
--- /dev/null
+++ b/tests/OverloadedStrings.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module OverloadedStrings (testOverloadedStrings) where
+
+import Data.DList.NonEmpty
+
+testOverloadedStrings :: IO ()
+testOverloadedStrings = print $ "OverloadedStrings:" `append` " success"
