dlist-nonempty (empty) → 0.1
raw patch · 10 files changed
+664/−0 lines, 10 filesdep +Cabaldep +QuickCheckdep +basesetup-changed
Dependencies added: Cabal, QuickCheck, base, base-compat, criterion, deepseq, dlist, dlist-instances, dlist-nonempty, quickcheck-instances, semigroupoids, semigroups
Files
- LICENSE +31/−0
- README.md +33/−0
- Setup.lhs +3/−0
- bench/Main.hs +29/−0
- dlist-nonempty.cabal +84/−0
- src/Data/DList/NonEmpty.hs +47/−0
- src/Data/DList/NonEmpty/Internal.hs +268/−0
- src/Data/DList/NonEmpty/Unsafe.hs +11/−0
- tests/Main.hs +150/−0
- tests/OverloadedStrings.hs +8/−0
+ LICENSE view
@@ -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.
+ README.md view
@@ -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)+```
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ bench/Main.hs view
@@ -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]+ ]+ ]
+ dlist-nonempty.cabal view
@@ -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
+ src/Data/DList/NonEmpty.hs view
@@ -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
+ src/Data/DList/NonEmpty/Internal.hs view
@@ -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
+ src/Data/DList/NonEmpty/Unsafe.hs view
@@ -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
+ tests/Main.hs view
@@ -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
+ tests/OverloadedStrings.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE OverloadedStrings #-}++module OverloadedStrings (testOverloadedStrings) where++import Data.DList.NonEmpty++testOverloadedStrings :: IO ()+testOverloadedStrings = print $ "OverloadedStrings:" `append` " success"