base-compat 0.8.2 → 0.9.0
raw patch · 38 files changed
+1126/−38 lines, 38 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Control.Monad.Compat: (<$!>) :: Monad m => (a -> b) -> m a -> m b
- Control.Monad.Compat: foldM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
- Control.Monad.Compat: foldM_ :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m ()
- Control.Monad.Compat: forM :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)
- Control.Monad.Compat: forM_ :: (Foldable t, Monad m) => t a -> (a -> m b) -> m ()
- Control.Monad.Compat: guard :: Alternative f => Bool -> f ()
- Control.Monad.Compat: mapM :: Traversable t => forall a (m :: * -> *) b. Monad m => (a -> m b) -> t a -> m (t b)
- Control.Monad.Compat: mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m ()
- Control.Monad.Compat: msum :: (Foldable t, MonadPlus m) => t (m a) -> m a
- Control.Monad.Compat: sequence :: Traversable t => forall (m :: * -> *) a. Monad m => t (m a) -> m (t a)
- Control.Monad.Compat: sequence_ :: (Foldable t, Monad m) => t (m a) -> m ()
- Control.Monad.Compat: unless :: Applicative f => Bool -> f () -> f ()
- Control.Monad.Compat: when :: Applicative f => Bool -> f () -> f ()
- Data.Foldable.Compat: length :: Foldable t => t a -> Int
- Data.Foldable.Compat: null :: Foldable t => t a -> Bool
- Data.List.Compat: all :: Foldable t => (a -> Bool) -> t a -> Bool
- Data.List.Compat: and :: Foldable t => t Bool -> Bool
- Data.List.Compat: any :: Foldable t => (a -> Bool) -> t a -> Bool
- Data.List.Compat: concat :: Foldable t => t [a] -> [a]
- Data.List.Compat: concatMap :: Foldable t => (a -> [b]) -> t a -> [b]
- Data.List.Compat: elem :: (Foldable t, Eq a) => a -> t a -> Bool
- Data.List.Compat: find :: Foldable t => (a -> Bool) -> t a -> Maybe a
- Data.List.Compat: foldl :: Foldable t => forall b a. (b -> a -> b) -> b -> t a -> b
- Data.List.Compat: foldl' :: Foldable t => forall b a. (b -> a -> b) -> b -> t a -> b
- Data.List.Compat: foldl1 :: Foldable t => forall a. (a -> a -> a) -> t a -> a
- Data.List.Compat: foldr :: Foldable t => forall a b. (a -> b -> b) -> b -> t a -> b
- Data.List.Compat: foldr1 :: Foldable t => forall a. (a -> a -> a) -> t a -> a
- Data.List.Compat: isSubsequenceOf :: Eq a => [a] -> [a] -> Bool
- Data.List.Compat: length :: Foldable t => t a -> Int
- Data.List.Compat: mapAccumL :: Traversable t => (a -> b -> (a, c)) -> a -> t b -> (a, t c)
- Data.List.Compat: mapAccumR :: Traversable t => (a -> b -> (a, c)) -> a -> t b -> (a, t c)
- Data.List.Compat: maximum :: (Foldable t, Ord a) => t a -> a
- Data.List.Compat: maximumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a
- Data.List.Compat: minimum :: (Foldable t, Ord a) => t a -> a
- Data.List.Compat: minimumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a
- Data.List.Compat: notElem :: (Foldable t, Eq a) => a -> t a -> Bool
- Data.List.Compat: nub :: Eq a => [a] -> [a]
- Data.List.Compat: nubBy :: (a -> a -> Bool) -> [a] -> [a]
- Data.List.Compat: null :: Foldable t => t a -> Bool
- Data.List.Compat: or :: Foldable t => t Bool -> Bool
- Data.List.Compat: product :: (Foldable t, Num a) => t a -> a
- Data.List.Compat: scanl' :: (b -> a -> b) -> b -> [a] -> [b]
- Data.List.Compat: sortOn :: Ord b => (a -> b) -> [a] -> [a]
- Data.List.Compat: sum :: (Foldable t, Num a) => t a -> a
- Data.List.Compat: uncons :: [a] -> Maybe (a, [a])
- Data.List.Compat: union :: Eq a => [a] -> [a] -> [a]
- Data.List.Compat: unionBy :: (a -> a -> Bool) -> [a] -> [a] -> [a]
+ Control.Concurrent.Compat: forkFinally :: IO a -> (Either SomeException a -> IO ()) -> IO ThreadId
+ Control.Concurrent.Compat: forkOSWithUnmask :: ((forall a. IO a -> IO a) -> IO ()) -> IO ThreadId
+ Control.Monad.Compat: filterM :: (Applicative m) => (a -> m Bool) -> [a] -> m [a]
+ Control.Monad.Compat: forever :: (Applicative f) => f a -> f b
+ Control.Monad.Compat: mapAndUnzipM :: (Applicative m) => (a -> m (b, c)) -> [a] -> m ([b], [c])
+ Control.Monad.Compat: replicateM :: (Applicative m) => Int -> m a -> m [a]
+ Control.Monad.Compat: replicateM_ :: (Applicative m) => Int -> m a -> m ()
+ Control.Monad.Compat: zipWithM :: (Applicative m) => (a -> b -> m c) -> [a] -> [b] -> m [c]
+ Control.Monad.Compat: zipWithM_ :: (Applicative m) => (a -> b -> m c) -> [a] -> [b] -> m ()
+ Control.Monad.ST.Lazy.Unsafe.Compat: unsafeIOToST :: IO a -> ST s a
+ Control.Monad.ST.Lazy.Unsafe.Compat: unsafeInterleaveST :: ST s a -> ST s a
+ Control.Monad.ST.Unsafe.Compat: unsafeIOToST :: IO a -> ST s a
+ Control.Monad.ST.Unsafe.Compat: unsafeInterleaveST :: ST s a -> ST s a
+ Control.Monad.ST.Unsafe.Compat: unsafeSTToIO :: ST s a -> IO a
+ Data.Functor.Const.Compat: Const :: a -> Const a b
+ Data.Functor.Const.Compat: [getConst] :: Const a b -> a
+ Data.Functor.Const.Compat: newtype Const a b :: * -> * -> *
+ Data.IORef.Compat: atomicModifyIORef' :: IORef a -> (a -> (a, b)) -> IO b
+ Data.IORef.Compat: atomicWriteIORef :: IORef a -> a -> IO ()
+ Data.IORef.Compat: modifyIORef' :: IORef a -> (a -> a) -> IO ()
+ Data.Ratio.Compat: denominator :: Ratio a -> a
+ Data.Ratio.Compat: numerator :: Ratio a -> a
+ Data.STRef.Compat: modifySTRef' :: STRef s a -> (a -> a) -> ST s ()
+ Data.String.Compat: lines :: String -> [String]
+ Data.String.Compat: type String = [Char]
+ Data.String.Compat: unlines :: [String] -> String
+ Data.String.Compat: unwords :: [String] -> String
+ Data.String.Compat: words :: String -> [String]
+ Foreign.ForeignPtr.Safe.Compat: addForeignPtrFinalizer :: FinalizerPtr a -> ForeignPtr a -> IO ()
+ Foreign.ForeignPtr.Safe.Compat: addForeignPtrFinalizerEnv :: FinalizerEnvPtr env a -> Ptr env -> ForeignPtr a -> IO ()
+ Foreign.ForeignPtr.Safe.Compat: castForeignPtr :: ForeignPtr a -> ForeignPtr b
+ Foreign.ForeignPtr.Safe.Compat: data ForeignPtr a :: * -> *
+ Foreign.ForeignPtr.Safe.Compat: finalizeForeignPtr :: ForeignPtr a -> IO ()
+ Foreign.ForeignPtr.Safe.Compat: mallocForeignPtr :: Storable a => IO (ForeignPtr a)
+ Foreign.ForeignPtr.Safe.Compat: mallocForeignPtrArray :: Storable a => Int -> IO (ForeignPtr a)
+ Foreign.ForeignPtr.Safe.Compat: mallocForeignPtrArray0 :: Storable a => Int -> IO (ForeignPtr a)
+ Foreign.ForeignPtr.Safe.Compat: mallocForeignPtrBytes :: Int -> IO (ForeignPtr a)
+ Foreign.ForeignPtr.Safe.Compat: newForeignPtr :: FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
+ Foreign.ForeignPtr.Safe.Compat: newForeignPtrEnv :: FinalizerEnvPtr env a -> Ptr env -> Ptr a -> IO (ForeignPtr a)
+ Foreign.ForeignPtr.Safe.Compat: newForeignPtr_ :: Ptr a -> IO (ForeignPtr a)
+ Foreign.ForeignPtr.Safe.Compat: touchForeignPtr :: ForeignPtr a -> IO ()
+ Foreign.ForeignPtr.Safe.Compat: type FinalizerEnvPtr env a = FunPtr (Ptr env -> Ptr a -> IO ())
+ Foreign.ForeignPtr.Safe.Compat: type FinalizerPtr a = FunPtr (Ptr a -> IO ())
+ Foreign.ForeignPtr.Safe.Compat: withForeignPtr :: ForeignPtr a -> (Ptr a -> IO b) -> IO b
+ Foreign.ForeignPtr.Unsafe.Compat: unsafeForeignPtrToPtr :: ForeignPtr a -> Ptr a
+ Foreign.Marshal.Unsafe.Compat: unsafeLocalState :: IO a -> a
+ Prelude.Compat: errorWithoutStackTrace :: [Char] -> a
+ System.IO.Unsafe.Compat: unsafeDupablePerformIO :: IO a -> a
+ System.IO.Unsafe.Compat: unsafeFixIO :: (a -> IO a) -> IO a
- Control.Monad.Compat: class Monad (m :: * -> *)
+ Control.Monad.Compat: class Applicative m => Monad (m :: * -> *)
- Control.Monad.Compat: class Monad m => MonadPlus (m :: * -> *)
+ Control.Monad.Compat: class (Alternative m, Monad m) => MonadPlus (m :: * -> *)
- Debug.Trace.Compat: traceM :: Monad m => String -> m ()
+ Debug.Trace.Compat: traceM :: (Applicative f) => String -> f ()
- Debug.Trace.Compat: traceShowM :: (Show a, Monad m) => a -> m ()
+ Debug.Trace.Compat: traceShowM :: (Show a, Applicative f) => a -> f ()
- Prelude.Compat: class Monad (m :: * -> *)
+ Prelude.Compat: class Applicative m => Monad (m :: * -> *)
Files
- CHANGES.markdown +23/−0
- LICENSE +1/−1
- README.markdown +141/−16
- base-compat.cabal +48/−5
- src/Control/Concurrent/Compat.hs +44/−0
- src/Control/Monad/Compat.hs +69/−3
- src/Control/Monad/ST/Lazy/Unsafe/Compat.hs +12/−0
- src/Control/Monad/ST/Unsafe/Compat.hs +13/−0
- src/Data/Complex/Compat.hs +50/−0
- src/Data/Functor/Const/Compat.hs +4/−0
- src/Data/IORef/Compat.hs +42/−0
- src/Data/Ratio/Compat.hs +32/−0
- src/Data/STRef/Compat.hs +21/−0
- src/Data/String/Compat.hs +15/−0
- src/Debug/Trace/Compat.hs +27/−9
- src/Foreign/ForeignPtr/Safe/Compat.hs +34/−0
- src/Foreign/ForeignPtr/Unsafe/Compat.hs +11/−0
- src/Foreign/Marshal/Safe/Compat.hs +16/−0
- src/Foreign/Marshal/Unsafe/Compat.hs +11/−0
- src/Prelude/Compat.hs +17/−4
- src/System/IO/Unsafe/Compat.hs +35/−0
- test/Control/Monad/CompatSpec.hs +16/−0
- test/Data/Bits/CompatSpec.hs +34/−0
- test/Data/Bool/CompatSpec.hs +18/−0
- test/Data/Either/CompatSpec.hs +25/−0
- test/Data/Function/CompatSpec.hs +13/−0
- test/Data/Functor/CompatSpec.hs +17/−0
- test/Data/IORef/CompatSpec.hs +22/−0
- test/Data/List/CompatSpec.hs +43/−0
- test/Data/Monoid/CompatSpec.hs +16/−0
- test/Data/STRef/CompatSpec.hs +19/−0
- test/Data/Version/CompatSpec.hs +10/−0
- test/Data/Word/CompatSpec.hs +22/−0
- test/Foreign/Marshal/Alloc/CompatSpec.hs +17/−0
- test/Foreign/Marshal/Utils/CompatSpec.hs +20/−0
- test/Numeric/CompatSpec.hs +24/−0
- test/System/Environment/CompatSpec.hs +120/−0
- test/Text/Read/CompatSpec.hs +24/−0
CHANGES.markdown view
@@ -1,3 +1,26 @@+## Changes in 0.9.0+ - Sync with `base-4.9`/GHC 8.0+ - Weakened `RealFloat` constraints on `realPart`, `imagPart`, `conjugate`,+ `mkPolar`, and `cis` in `Data.Complex.Compat`+ - Backport `Foreign.ForeignPtr.Safe` and `Foreign.Marshal.Safe`+ - Generalize `filterM`, `forever`, `mapAndUnzipM`, `zipWithM`, `zipWithM_`,+ `replicateM`, and `replicateM_` in `Control.Monad` from `Monad` to+ `Applicative`+ - Backport `.Unsafe.Compat` modules (for `Control.Monad.ST`,+ `Control.Monad.ST.Lazy`, `Foreign.ForeignPtr`, and `Foreign.Marshal`)+ - Backport `forkFinally` and `forkOSWithUnmask` to `Control.Concurrent.Compat`+ - Backport `Data.Functor.Const`+ - Backport `modifyIORef'`, `atomicModifyIORef'` and `atomicWriteIORef` to+ `Data.IORef.Compat`+ - `Data.Ratio.{denominator,numerator}` have no `Integral` constraint anymore+ - Backport `modifySTRef'` to `Data.STRef.Compat`+ - Export `String`, `lines`, `words`, `unlines`, and `unwords` to+ `Data.String.Compat`+ - Generalize `Debug.Trace.{traceM, traceShowM}` from `Monad` to `Applicative`+ - Backport `errorWithoutStackTrace` to `Prelude.Compat`+ - Backport `unsafeFixIO` and `unsafeDupablePerformIO` to+ `System.IO.Unsafe.Compat`+ ## Changes in 0.8.2 - Backport `bitDefault`, `testBitDefault`, and `popCountDefault` in `Data.Bits.Compat` to all versions of `base`
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2012-2015 Simon Hengel <sol@typeful.net> and Ryan Scott <ryan.gl.scott@ku.edu>+Copyright (c) 2012-2015 Simon Hengel <sol@typeful.net> and Ryan Scott <ryan.gl.scott@gmail.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal
README.markdown view
@@ -1,4 +1,20 @@-# A compatibility layer for `base` [](http://hackage.haskell.org/package/base-compat) [](https://travis-ci.org/haskell-compat/base-compat)+# A compatibility layer for `base`+[][Hackage: base-compat]+[](http://packdeps.haskellers.com/reverse/base-compat)+[][Haskell.org]+[][tl;dr Legal: MIT]+[](https://travis-ci.org/haskell-compat/base-compat)++[Hackage: base-compat]:+ http://hackage.haskell.org/package/base-compat+ "base-compat package on Hackage"+[Haskell.org]:+ http://www.haskell.org+ "The Haskell Programming Language"+[tl;dr Legal: MIT]:+ https://tldrlegal.com/license/mit-license+ "MIT License"+ ## Scope The scope of `base-compat` is to provide functions available in later versions@@ -12,13 +28,19 @@ package [`base-orphans`](https://github.com/haskell-compat/base-orphans) for that. +In addition, `base-compat` only backports functions. In particular, we+purposefully do not backport data types or type classes introduced in newer+versions of `base`. For more info, see the+[Data types and type classes](#data-types-and-type-classes)+section.+ ## Basic usage In your cabal file, you should have something like this: ``` build-depends: base >= 4.3- , base-compat >= 0.8.0+ , base-compat >= 0.9.0 ``` Then, lets say you want to use the `isRight` function introduced with@@ -83,7 +105,7 @@ ### For compatibility with the latest released version of `base` * `Prelude.Compat` incorporates the AMP/Foldable/Traversable changes and- exposes the same interface as `Prelude` from `base-4.8.0.0`+ exposes the same interface as `Prelude` from `base-4.9.0.0` * `System.IO.Error.catch` is not re-exported from `Prelude.Compat` for older versions of `base` * `Text.Read.Compat.readMaybe`@@ -93,13 +115,19 @@ * Added `toIntegralSized` to `Data.Bits.Compat` (if using `base-4.7`) * Added `bool` function to `Data.Bool.Compat` * Added `isLeft` and `isRight` to `Data.Either.Compat`+ * Added `forkFinally` to `Control.Concurrent.Compat` * Added `withMVarMasked` function to `Control.Concurrent.MVar.Compat` * Added `(<$!>)` function to `Control.Monad.Compat`+ * Weakened `RealFloat` constraints on `realPart`, `imagPart`, `conjugate`, `mkPolar`,+ and `cis` in `Data.Complex.Compat` * Added `($>)` and `void` functions to `Data.Functor.Compat` * `(&)` function to `Data.Function.Compat` * `($>)` and `void` functions to `Data.Functor.Compat`+ * `modifyIORef'`, `atomicModifyIORef'` and `atomicWriteIORef` to `Data.IORef.Compat` * `dropWhileEnd`, `isSubsequenceOf`, `sortOn`, and `uncons` functions to `Data.List.Compat` * Correct versions of `nub`, `nubBy`, `union`, and `unionBy` to `Data.List.Compat`+ * `modifySTRef'` to `Data.STRef.Compat`+ * `String`, `lines`, `words`, `unlines`, and `unwords` to `Data.String.Compat` * `makeVersion` function to `Data.Version.Compat` * `traceId`, `traceShowId`, `traceM`, and `traceShowM` functions to `Debug.Trace.Compat` * `byteSwap16`, `byteSwap32`, and `byteSwap64` to `Data.Word.Compat`@@ -109,9 +137,114 @@ * Added `Data.List.Compat.scanl'` * `showFFloatAlt` and `showGFloatAlt` to `Numeric.Compat` * `lookupEnv`, `setEnv` and `unsetEnv` to `System.Environment.Compat`+ * `unsafeFixIO` and `unsafeDupablePerformIO` to `System.IO.Unsafe.IO` -## Supported versions of GHC/base+## What is not covered +### Data types and type classes+`base-compat` purposefully does not export any data types or type classes that+were introduced in more recent versions of `base`. The main reasoning for this+policy is that it is not some data types and type classes have had their APIs+change in different versions of `base`, which makes having a consistent+compatibility API for them practically impossible.++As an example, consider the `FiniteBits` type class. It was introduced in+[`base-4.7.0.0`](http://hackage.haskell.org/package/base-4.7.0.0/docs/Data-Bits.html#t:FiniteBits)+with the following API:++```haskell+class Bits b => FiniteBits b where+ finiteBitSize :: b -> Int+```++However, in [`base-4.8.0.0`](http://hackage.haskell.org/package/base-4.8.0.0/docs/Data-Bits.html#t:FiniteBits),+`FiniteBits` gained additional functions:++```haskell+class Bits b => FiniteBits b where+ finiteBitSize :: b -> Int+ countLeadingZeros :: b -> Int+ countTrailingZeros :: b -> Int+```++This raises the question: how can `FiniteBits` be backported consistently+across all versions of `base`? One approach is to backport the API exposed in+`base-4.8.0.0` on versions prior to `4.7.0.0`. The problem with this is that+`countLeadingZeros` and `countTrailingZeros` are not exposed in `base-4.7.0.0`,+so instances of `FiniteBits` would have to be declared like this:++```haskell+instance FiniteBits Foo where+ finiteBitSize = ...+#if MIN_VERSION_base(4,8,0) || !(MIN_VERSION_base(4,7,0))+ countLeadingZeros = ...+ countTrailingZeros = ...+#endif+```++This is a very unsatisfactory solution, and for this reason, we do not pursue+it. For similar reasons, we do not backport data types.++### Other compatibility packages++If you _really_ need your favorite data type or type class in `base` to be+backported, you might be in luck, since several data types have their own+compatibility packages on Hackage. Here is a list of such packages:++* [`bifunctors`](http://hackage.haskell.org/package/bifunctors)+ for the [`Bifunctor`](http://hackage.haskell.org/package/base-4.8.0.0/docs/Data-Bifunctor.html#t:Bifunctor)+ type class, introduced in `base-4.8.0.0`+* [`generic-deriving`](http://hackage.haskell.org/package/generic-deriving)+ for everything in the [`GHC.Generics`](http://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Generics.html)+ module, introduced to `ghc-prim` in GHC 7.2 (and later moved to `base-4.6.0.0`)+* [`nats`](http://hackage.haskell.org/package/nats)+ for the [`Natural`](http://hackage.haskell.org/package/base-4.8.0.0/docs/Numeric-Natural.html)+ data type, introduced in `base-4.8.0.0`+* [`semigroups`](http://hackage.haskell.org/package/semigroups)+ for the [`Semigroup`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Semigroup)+ typeclass and the+ [`NonEmpty`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-List-NonEmpty.html#t:NonEmpty),+ [`Min`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Min),+ [`Max`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Max),+ [`First`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:First),+ [`Last`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Last),+ [`WrappedMonoid`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:WrappedMonoid),+ [`Option`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Option),+ and+ [`Arg`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Arg)+ data types, introduced in `base-4.9.0.0`+* [`tagged`](http://hackage.haskell.org/package/tagged)+ for the [`Proxy`](http://hackage.haskell.org/package/base-4.7.0.0/docs/Data-Proxy.html#t:Proxy)+ data type, introduced in `base-4.7.0.0`+* [`transformers`](http://hackage.haskell.org/package/transformers)+ for:+ * The [`Identity`](http://hackage.haskell.org/package/base-4.8.0.0/docs/Data-Functor-Identity.html#t:Identity)+ data type, introduced in `base-4.8.0.0`+ * The [`MonadIO`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Control-Monad-IO-Class.html#t:MonadIO),+ [`Eq1`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Classes.html#t:Eq1),+ [`Eq2`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Classes.html#t:Eq2),+ [`Ord1`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Classes.html#t:Ord1),+ [`Ord2`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Classes.html#t:Ord2),+ [`Read1`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Classes.html#t:Read1),+ [`Read2`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Classes.html#t:Read2),+ [`Show1`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Classes.html#t:Show1),+ and+ [`Show2`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Classes.html#t:Show2)+ typeclasses; and the+ [`Compose`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Compose.html#t:Compose),+ [`Product`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Product.html#t:Product),+ and+ [`Sum`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Sum.html#t:Sum)+ data types, introduced in `base-4.9.0.0`+* [`void`](http://hackage.haskell.org/package/void)+ for the [`Void`](http://hackage.haskell.org/package/base-4.8.0.0/docs/Data-Void.html#t:Void)+ data type, introduced in `base-4.8.0.0`++## Supported versions of GHC/`base`++ * `ghc-8.0.1` / `base-4.9.0.0`+ * `ghc-7.10.3` / `base-4.8.2.0`+ * `ghc-7.10.2` / `base-4.8.1.0` * `ghc-7.10.1` / `base-4.8.0.0` * `ghc-7.8.4` / `base-4.7.0.2` * `ghc-7.8.3` / `base-4.7.0.1`@@ -129,16 +262,8 @@ * `ghc-7.0.2` / `base-4.3.1.0` * `ghc-7.0.1` / `base-4.3.0.0` -Patches are welcome; add tests for new code!--## Development--For `Prelude.Compat` there is an `Prelude.index` file that was generated from-the output of-- ghc --show-iface Prelude.hi--To verify that `Prelude.Compat` matches the specification given in-`Prelude.types` run:+We also make an attempt to keep `base-compat` building with GHC HEAD, but due+to its volatility, it may not work at any given point in time. If it doesn't,+please report it! - ./check-Prelude.sh+Patches are welcome; add tests for new code!
base-compat.cabal view
@@ -1,5 +1,5 @@ name: base-compat-version: 0.8.2+version: 0.9.0 license: MIT license-file: LICENSE copyright: (c) 2012-2015 Simon Hengel,@@ -7,10 +7,10 @@ (c) 2015 Ryan Scott author: Simon Hengel <sol@typeful.net>, João Cristóvão <jmacristovao@gmail.com>,- Ryan Scott <ryan.gl.scott@ku.edu>+ Ryan Scott <ryan.gl.scott@gmail.com> maintainer: Simon Hengel <sol@typeful.net>, João Cristóvão <jmacristovao@gmail.com>,- Ryan Scott <ryan.gl.scott@ku.edu>+ Ryan Scott <ryan.gl.scott@gmail.com> build-type: Simple cabal-version: >= 1.8 category: Compatibility@@ -24,9 +24,20 @@ for recent changes. . Note that @base-compat@ does not add any orphan instances.- There is a separate package- @<http://hackage.haskell.org/package/base-orphans base-orphans>@+ There is a separate package,+ @<http://hackage.haskell.org/package/base-orphans base-orphans>@, for that.+ .+ In addition, `base-compat` does not backport any data types+ or type classes. See+ @<https://github.com/haskell-compat/base-compat#data-types-and-type-classes this section of the README>@+ for more info.+tested-with: GHC == 7.0.1, GHC == 7.0.2, GHC == 7.0.3, GHC == 7.0.4+ , GHC == 7.2.1, GHC == 7.2.2+ , GHC == 7.4.1, GHC == 7.4.2+ , GHC == 7.6.1, GHC == 7.6.2, GHC == 7.6.3+ , GHC == 7.8.1, GHC == 7.8.2, GHC == 7.8.3, GHC == 7.8.4+ , GHC == 7.10.1, GHC == 7.10.2, GHC == 7.10.3 extra-source-files: CHANGES.markdown, README.markdown source-repository head@@ -47,28 +58,42 @@ src exposed-modules:+ Control.Concurrent.Compat Control.Concurrent.MVar.Compat Control.Monad.Compat+ Control.Monad.ST.Lazy.Unsafe.Compat+ Control.Monad.ST.Unsafe.Compat Data.Bits.Compat Data.Bool.Compat+ Data.Complex.Compat Data.Either.Compat Data.Foldable.Compat Data.Function.Compat Data.Functor.Compat+ Data.Functor.Const.Compat+ Data.IORef.Compat Data.List.Compat Data.Monoid.Compat+ Data.Ratio.Compat+ Data.STRef.Compat+ Data.String.Compat Data.Version.Compat Data.Word.Compat Debug.Trace.Compat Foreign.Compat+ Foreign.ForeignPtr.Safe.Compat+ Foreign.ForeignPtr.Unsafe.Compat Foreign.Marshal.Alloc.Compat Foreign.Marshal.Array.Compat Foreign.Marshal.Compat+ Foreign.Marshal.Safe.Compat+ Foreign.Marshal.Unsafe.Compat Foreign.Marshal.Utils.Compat Numeric.Compat Prelude.Compat System.Environment.Compat System.Exit.Compat+ System.IO.Unsafe.Compat Text.Read.Compat test-suite spec@@ -80,6 +105,24 @@ test main-is: Spec.hs+ other-modules:+ Control.Monad.CompatSpec+ Data.Bits.CompatSpec+ Data.Bool.CompatSpec+ Data.Either.CompatSpec+ Data.Function.CompatSpec+ Data.Functor.CompatSpec+ Data.IORef.CompatSpec+ Data.List.CompatSpec+ Data.Monoid.CompatSpec+ Data.STRef.CompatSpec+ Data.Version.CompatSpec+ Data.Word.CompatSpec+ Foreign.Marshal.Alloc.CompatSpec+ Foreign.Marshal.Utils.CompatSpec+ Numeric.CompatSpec+ System.Environment.CompatSpec+ Text.Read.CompatSpec build-depends: base >= 4.3 && < 5 , base-compat
+ src/Control/Concurrent/Compat.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE CPP, NoImplicitPrelude #-}+{-# LANGUAGE RankNTypes #-}+module Control.Concurrent.Compat (+ module Base+, forkFinally+, forkOSWithUnmask+) where++import Control.Concurrent as Base++#if !(MIN_VERSION_base(4,6,0))+import Control.Exception+#endif++#if !(MIN_VERSION_base(4,9,0))+import GHC.IO (unsafeUnmask)+import Prelude+#endif++#if !(MIN_VERSION_base(4,6,0))+-- | fork a thread and call the supplied function when the thread is about+-- to terminate, with an exception or a returned value. The function is+-- called with asynchronous exceptions masked.+--+-- > forkFinally action and_then =+-- > mask $ \restore ->+-- > forkIO $ try (restore action) >>= and_then+--+-- This function is useful for informing the parent when a child+-- terminates, for example.+--+-- /Since: 4.6.0.0/+forkFinally :: IO a -> (Either SomeException a -> IO ()) -> IO ThreadId+forkFinally action and_then =+ mask $ \restore ->+ forkIO $ try (restore action) >>= and_then+#endif++#if !(MIN_VERSION_base(4,9,0))+-- | Like 'forkIOWithUnmask', but the child thread is a bound thread,+-- as with 'forkOS'.+forkOSWithUnmask :: ((forall a . IO a -> IO a) -> IO ()) -> IO ThreadId+forkOSWithUnmask io = forkOS (io unsafeUnmask)+#endif
src/Control/Monad/Compat.hs view
@@ -19,13 +19,30 @@ , (<$!>) #endif+#if !(MIN_VERSION_base(4,9,0))+, forever+, filterM+, mapAndUnzipM+, zipWithM+, zipWithM_+, replicateM+, replicateM_+#endif ) where -#if MIN_VERSION_base(4,8,0)+#if MIN_VERSION_base(4,9,0) import Control.Monad as Base #else import Control.Monad as Base hiding (- foldM+ forever+ , filterM+ , mapAndUnzipM+ , zipWithM+ , zipWithM_+ , replicateM+ , replicateM_+# if !(MIN_VERSION_base(4,8,0))+ , foldM , foldM_ , forM , forM_@@ -37,8 +54,9 @@ , sequence_ , unless , when+# endif )-import Control.Applicative (Alternative(..))+import Control.Applicative import Data.Foldable.Compat import Data.Traversable import Prelude.Compat@@ -115,4 +133,52 @@ x <- m let z = f x z `seq` return z+#endif++#if !(MIN_VERSION_base(4,9,0))+-- | @'forever' act@ repeats the action infinitely.+forever :: (Applicative f) => f a -> f b+{-# INLINE forever #-}+forever a = let a' = a *> a' in a'+-- Use explicit sharing here, as it is prevents a space leak regardless of+-- optimizations.++-- | This generalizes the list-based 'filter' function.+{-# INLINE filterM #-}+filterM :: (Applicative m) => (a -> m Bool) -> [a] -> m [a]+filterM p = foldr (\ x -> liftA2 (\ flg -> if flg then (x:) else id) (p x)) (pure [])++-- | The 'mapAndUnzipM' function maps its first argument over a list, returning+-- the result as a pair of lists. This function is mainly used with complicated+-- data structures or a state-transforming monad.+mapAndUnzipM :: (Applicative m) => (a -> m (b,c)) -> [a] -> m ([b], [c])+{-# INLINE mapAndUnzipM #-}+mapAndUnzipM f xs = unzip <$> traverse f xs++-- | The 'zipWithM' function generalizes 'zipWith' to arbitrary applicative functors.+zipWithM :: (Applicative m) => (a -> b -> m c) -> [a] -> [b] -> m [c]+{-# INLINE zipWithM #-}+zipWithM f xs ys = sequenceA (zipWith f xs ys)++-- | 'zipWithM_' is the extension of 'zipWithM' which ignores the final result.+zipWithM_ :: (Applicative m) => (a -> b -> m c) -> [a] -> [b] -> m ()+{-# INLINE zipWithM_ #-}+zipWithM_ f xs ys = sequenceA_ (zipWith f xs ys)++-- | @'replicateM' n act@ performs the action @n@ times,+-- gathering the results.+replicateM :: (Applicative m) => Int -> m a -> m [a]+{-# INLINEABLE replicateM #-}+{-# SPECIALISE replicateM :: Int -> IO a -> IO [a] #-}+{-# SPECIALISE replicateM :: Int -> Maybe a -> Maybe [a] #-}+replicateM 0 _ = pure []+replicateM n x = liftA2 (:) x (replicateM (pred n) x)++-- | Like 'replicateM', but discards the result.+replicateM_ :: (Applicative m) => Int -> m a -> m ()+{-# INLINEABLE replicateM_ #-}+{-# SPECIALISE replicateM_ :: Int -> IO a -> IO () #-}+{-# SPECIALISE replicateM_ :: Int -> Maybe a -> Maybe () #-}+replicateM_ 0 _ = pure ()+replicateM_ n x = x *> replicateM_ (pred n) x #endif
+ src/Control/Monad/ST/Lazy/Unsafe/Compat.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE CPP, NoImplicitPrelude #-}+module Control.Monad.ST.Lazy.Unsafe.Compat (+ -- * Unsafe operations+ unsafeInterleaveST+, unsafeIOToST+) where++#if MIN_VERSION_base(4,6,0)+import Control.Monad.ST.Lazy.Unsafe (unsafeInterleaveST, unsafeIOToST)+#else+import Control.Monad.ST.Lazy (unsafeInterleaveST, unsafeIOToST)+#endif
+ src/Control/Monad/ST/Unsafe/Compat.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE CPP, NoImplicitPrelude #-}+module Control.Monad.ST.Unsafe.Compat (+ -- * Unsafe operations+ unsafeInterleaveST+, unsafeIOToST+, unsafeSTToIO+) where++#if MIN_VERSION_base(4,6,0)+import Control.Monad.ST.Unsafe (unsafeInterleaveST, unsafeIOToST, unsafeSTToIO)+#else+import Control.Monad.ST (unsafeInterleaveST, unsafeIOToST, unsafeSTToIO)+#endif
+ src/Data/Complex/Compat.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE CPP, NoImplicitPrelude #-}+module Data.Complex.Compat (+ module Base+#if MIN_VERSION_base(4,4,0) && !(MIN_VERSION_base(4,8,0))+, realPart+, imagPart+, mkPolar+, cis+, conjugate+#endif+) where++#if !(MIN_VERSION_base(4,4,0)) || MIN_VERSION_base(4,8,0)+import Data.Complex as Base+#else+import Data.Complex as Base hiding (+ realPart+ , imagPart+ , mkPolar+ , cis+ , conjugate+ )+import Prelude+#endif++#if MIN_VERSION_base(4,4,0) && !(MIN_VERSION_base(4,8,0))+-- | Extracts the real part of a complex number.+realPart :: Complex a -> a+realPart (x :+ _) = x++-- | Extracts the imaginary part of a complex number.+imagPart :: Complex a -> a+imagPart (_ :+ y) = y++-- | The conjugate of a complex number.+{-# SPECIALISE conjugate :: Complex Double -> Complex Double #-}+conjugate :: Num a => Complex a -> Complex a+conjugate (x:+y) = x :+ (-y)++-- | Form a complex number from polar components of magnitude and phase.+{-# SPECIALISE mkPolar :: Double -> Double -> Complex Double #-}+mkPolar :: Floating a => a -> a -> Complex a+mkPolar r theta = r * cos theta :+ r * sin theta++-- | @'cis' t@ is a complex value with magnitude @1@+-- and phase @t@ (modulo @2*'pi'@).+{-# SPECIALISE cis :: Double -> Complex Double #-}+cis :: Floating a => a -> Complex a+cis theta = cos theta :+ sin theta+#endif
+ src/Data/Functor/Const/Compat.hs view
@@ -0,0 +1,4 @@+{-# LANGUAGE CPP, NoImplicitPrelude #-}+module Data.Functor.Const.Compat (Const(..)) where++import Control.Applicative (Const(..))
+ src/Data/IORef/Compat.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE CPP, NoImplicitPrelude #-}+module Data.IORef.Compat (+ module Base+, modifyIORef'+, atomicModifyIORef'+, atomicWriteIORef+) where++import Data.IORef as Base++#if !(MIN_VERSION_base(4,6,0))+import Prelude++-- |Strict version of 'modifyIORef'+--+-- /Since: 4.6.0.0/+modifyIORef' :: IORef a -> (a -> a) -> IO ()+modifyIORef' ref f = do+ x <- readIORef ref+ let x' = f x+ x' `seq` writeIORef ref x'++-- | Strict version of 'atomicModifyIORef'. This forces both the value stored+-- in the 'IORef' as well as the value returned.+--+-- /Since: 4.6.0.0/+atomicModifyIORef' :: IORef a -> (a -> (a,b)) -> IO b+atomicModifyIORef' ref f = do+ b <- atomicModifyIORef ref $ \a ->+ case f a of+ v@(a',_) -> a' `seq` v+ b `seq` return b++-- | Variant of 'writeIORef' with the \"barrier to reordering\" property that+-- 'atomicModifyIORef' has.+--+-- /Since: 4.6.0.0/+atomicWriteIORef :: IORef a -> a -> IO ()+atomicWriteIORef ref a = do+ x <- atomicModifyIORef ref (\_ -> (a, ()))+ x `seq` return ()+#endif
+ src/Data/Ratio/Compat.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE CPP, NoImplicitPrelude #-}+module Data.Ratio.Compat (+ module Base+#if MIN_VERSION_base(4,4,0) && !(MIN_VERSION_base(4,9,0))+, denominator+, numerator+#endif+) where++#if !(MIN_VERSION_base(4,4,0)) || MIN_VERSION_base(4,9,0)+import Data.Ratio as Base+#else+import Data.Ratio as Base hiding (+ denominator+ , numerator+ )+import GHC.Real (Ratio(..))+#endif++#if MIN_VERSION_base(4,4,0) && !(MIN_VERSION_base(4,9,0))+-- | Extract the numerator of the ratio in reduced form:+-- the numerator and denominator have no common factor and the denominator+-- is positive.+numerator :: Ratio a -> a+numerator (x :% _) = x++-- | Extract the denominator of the ratio in reduced form:+-- the numerator and denominator have no common factor and the denominator+-- is positive.+denominator :: Ratio a -> a+denominator (_ :% y) = y+#endif
+ src/Data/STRef/Compat.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE CPP, NoImplicitPrelude #-}+module Data.STRef.Compat (+ module Base+, modifySTRef'+) where++import Data.STRef as Base++#if !(MIN_VERSION_base(4,6,0))+import Control.Monad.ST (ST)+import Prelude (seq)++-- | Strict version of 'modifySTRef'+--+-- /Since: 4.6.0.0/+modifySTRef' :: STRef s a -> (a -> a) -> ST s ()+modifySTRef' ref f = do+ x <- readSTRef ref+ let x' = f x+ x' `seq` writeSTRef ref x'+#endif
+ src/Data/String/Compat.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE CPP, NoImplicitPrelude #-}+module Data.String.Compat (+ module Base+, String+, lines+, words+, unlines+, unwords+) where++import Data.String as Base++#if !(MIN_VERSION_base(4,4,0))+import Prelude (String, lines, words, unlines, unwords)+#endif
src/Debug/Trace/Compat.hs view
@@ -6,11 +6,21 @@ , traceM , traceShowM ) where++#if !(MIN_VERSION_base(4,7,0)) || MIN_VERSION_base(4,9,0) import Debug.Trace as Base+#else+import Debug.Trace as Base hiding (+ traceM+ , traceShowM+ )+#endif -#if !(MIN_VERSION_base(4,7,0))+#if !(MIN_VERSION_base(4,9,0)) import Prelude.Compat+#endif +#if !(MIN_VERSION_base(4,7,0)) {-| Like 'trace' but returns the message instead of a third value. @@ -26,12 +36,20 @@ -} traceShowId :: (Show a) => a -> a traceShowId a = trace (show a) a+#endif +#if !(MIN_VERSION_base(4,9,0)) {-|-Like 'trace' but returning unit in an arbitrary monad. Allows for convenient-use in do-notation. Note that the application of 'trace' is not an action in the-monad, as 'traceIO' is in the 'IO' monad.+Like 'trace' but returning unit in an arbitrary 'Applicative' context. Allows+for convenient use in do-notation. +Note that the application of 'traceM' is not an action in the 'Applicative'+context, as 'traceIO' is in the 'IO' type. While the fresh bindings in the+following example will force the 'traceM' expressions to be reduced every time+the @do@-block is executed, @traceM "not crashed"@ would only be reduced once,+and the message would only be printed once. If your monad is in 'MonadIO',+@liftIO . traceIO@ may be a better option.+ > ... = do > x <- ... > traceM $ "x: " ++ show x@@ -40,20 +58,20 @@ /Since: 4.7.0.0/ -}-traceM :: (Monad m) => String -> m ()-traceM string = trace string $ return ()+traceM :: (Applicative f) => String -> f ()+traceM string = trace string $ pure () {-| Like 'traceM', but uses 'show' on the argument to convert it to a 'String'. > ... = do > x <- ...-> traceMShow $ x+> traceShowM $ x > y <- ...-> traceMShow $ x + y+> traceShowM $ x + y /Since: 4.7.0.0/ -}-traceShowM :: (Show a, Monad m) => a -> m ()+traceShowM :: (Show a, Applicative f) => a -> f () traceShowM = traceM . show #endif
+ src/Foreign/ForeignPtr/Safe/Compat.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE CPP, NoImplicitPrelude #-}+module Foreign.ForeignPtr.Safe.Compat (+ -- * Finalised data pointers+ ForeignPtr+ , FinalizerPtr+#if defined(__HUGS__) || defined(__GLASGOW_HASKELL__)+ , FinalizerEnvPtr+#endif+ -- ** Basic operations+ , newForeignPtr+ , newForeignPtr_+ , addForeignPtrFinalizer+#if defined(__HUGS__) || defined(__GLASGOW_HASKELL__)+ , newForeignPtrEnv+ , addForeignPtrFinalizerEnv+#endif+ , withForeignPtr++#ifdef __GLASGOW_HASKELL__+ , finalizeForeignPtr+#endif++ -- ** Low-level operations+ , touchForeignPtr+ , castForeignPtr++ -- ** Allocating managed memory+ , mallocForeignPtr+ , mallocForeignPtrBytes+ , mallocForeignPtrArray+ , mallocForeignPtrArray0+ ) where++import Foreign.ForeignPtr
+ src/Foreign/ForeignPtr/Unsafe/Compat.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE CPP, NoImplicitPrelude #-}+module Foreign.ForeignPtr.Unsafe.Compat (+ -- ** Unsafe low-level operations+ unsafeForeignPtrToPtr+) where++#if MIN_VERSION_base(4,6,0)+import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)+#else+import Foreign.ForeignPtr (unsafeForeignPtrToPtr)+#endif
+ src/Foreign/Marshal/Safe/Compat.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE CPP, NoImplicitPrelude #-}+module Foreign.Marshal.Safe.Compat (+ -- | The module "Foreign.Marshal.Safe" re-exports the other modules in the+ -- @Foreign.Marshal@ hierarchy:+ module Foreign.Marshal.Alloc+ , module Foreign.Marshal.Array+ , module Foreign.Marshal.Error+ , module Foreign.Marshal.Pool+ , module Foreign.Marshal.Utils+ ) where++import Foreign.Marshal.Alloc+import Foreign.Marshal.Array+import Foreign.Marshal.Error+import Foreign.Marshal.Pool+import Foreign.Marshal.Utils
+ src/Foreign/Marshal/Unsafe/Compat.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE CPP, NoImplicitPrelude #-}+module Foreign.Marshal.Unsafe.Compat (+ -- * Unsafe functions+ unsafeLocalState+) where++#if MIN_VERSION_base(4,6,0)+import Foreign.Marshal.Unsafe (unsafeLocalState)+#else+import Foreign.Marshal (unsafeLocalState)+#endif
src/Prelude/Compat.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE CPP, NoImplicitPrelude #-} module Prelude.Compat (-#if MIN_VERSION_base(4,8,0)+#if MIN_VERSION_base(4,9,0) module Base #else either@@ -101,6 +101,7 @@ , (||) , ($) , error+, errorWithoutStackTrace , undefined , seq @@ -257,7 +258,7 @@ ) where -#if MIN_VERSION_base(4,8,0)+#if MIN_VERSION_base(4,9,0) import Prelude as Base @@ -290,9 +291,21 @@ , sum ) -import Data.Word import Data.Foldable.Compat import Data.Traversable-import Data.Monoid++# if !(MIN_VERSION_base(4,8,0)) import Control.Applicative+import Data.Monoid+import Data.Word+# endif+#endif++#if !(MIN_VERSION_base(4,9,0))+-- | A variant of 'error' that does not produce a stack trace.+--+-- /Since: 4.9.0.0/+errorWithoutStackTrace :: [Char] -> a+errorWithoutStackTrace s = error s+{-# NOINLINE errorWithoutStackTrace #-} #endif
+ src/System/IO/Unsafe/Compat.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE CPP, NoImplicitPrelude #-}+module System.IO.Unsafe.Compat (+ module Base+, unsafeFixIO+, unsafeDupablePerformIO+) where++import System.IO.Unsafe as Base++#if !(MIN_VERSION_base(4,5,0))+import Control.Exception+import Data.IORef+import GHC.Base+import GHC.IO++-- | A slightly faster version of `System.IO.fixIO` that may not be+-- safe to use with multiple threads. The unsafety arises when used+-- like this:+--+-- > unsafeFixIO $ \r -> do+-- > forkIO (print r)+-- > return (...)+--+-- In this case, the child thread will receive a @NonTermination@+-- exception instead of waiting for the value of @r@ to be computed.+--+-- /Since: 4.5.0.0/+unsafeFixIO :: (a -> IO a) -> IO a+unsafeFixIO k = do+ ref <- newIORef (throw NonTermination)+ ans <- unsafeDupableInterleaveIO (readIORef ref)+ result <- k ans+ writeIORef ref result+ return result+#endif
+ test/Control/Monad/CompatSpec.hs view
@@ -0,0 +1,16 @@+module Control.Monad.CompatSpec (main, spec) where++import Test.Hspec++import Control.Monad.Compat+import Prelude ()+import Prelude.Compat++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "(<$!>)" $ do+ it "is a strict version of (<$>)" $ do+ not <$!> [True, False] `shouldBe` not <$> [True, False]
+ test/Data/Bits/CompatSpec.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE CPP #-}+module Data.Bits.CompatSpec (main, spec) where++import Test.Hspec+import Data.Bits.Compat++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "bitDefault" $+ it "sets the ith bit with all other bits clear" $ do+ bitDefault 0 `shouldBe` (1 :: Int)+ bitDefault 1 `shouldBe` (2 :: Int)+ bitDefault 2 `shouldBe` (4 :: Int)+ bitDefault 3 `shouldBe` (8 :: Int)+ describe "testBitDefault" $+ it "returns True if the nth bit of the argument is 1" $ do+ testBitDefault (10 :: Int) 0 `shouldBe` False+ testBitDefault (10 :: Int) 1 `shouldBe` True+ testBitDefault (10 :: Int) 2 `shouldBe` False+ testBitDefault (10 :: Int) 3 `shouldBe` True+ describe "popCountDefault" $+ it "returns the number of set bits in the argument" $ do+ popCountDefault (0 :: Int) `shouldBe` 0+ popCountDefault (1 :: Int) `shouldBe` 1+ popCountDefault (10 :: Int) `shouldBe` 2+#if MIN_VERSION_base(4,7,0)+ describe "toIntegralSized" $+ it "converts an Integral type to another as measured by bitSizeMaybe" $ do+ toIntegralSized (42 :: Integer) `shouldBe` (Just 42 :: Maybe Int)+ toIntegralSized (12345678901234567890 :: Integer) `shouldBe` (Nothing :: Maybe Int)+#endif
+ test/Data/Bool/CompatSpec.hs view
@@ -0,0 +1,18 @@+module Data.Bool.CompatSpec (main, spec) where++import Test.Hspec++import Data.Bool.Compat++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "bool" $ do+ it "evaluates to first parameter if condition is False" $ do+ bool "KO" "OK" False `shouldBe` "KO"++ it "evaluates to second parameter if condition is True" $ do+ bool "KO" "OK" True `shouldBe` "OK"+
+ test/Data/Either/CompatSpec.hs view
@@ -0,0 +1,25 @@+module Data.Either.CompatSpec (main, spec) where++import Test.Hspec++import Data.Either.Compat++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "isLeft" $ do+ it "returns True for a Left value" $ do+ isLeft (Left "23" :: Either String String) `shouldBe` True++ it "returns False for a Right value" $ do+ isLeft (Right "23" :: Either String String) `shouldBe` False++ describe "isRight" $ do+ it "returns False for a Left value" $ do+ isRight (Left "23" :: Either String String) `shouldBe` False++ it "returns True for a Right value" $ do+ isRight (Right "23" :: Either String String) `shouldBe` True+
+ test/Data/Function/CompatSpec.hs view
@@ -0,0 +1,13 @@+module Data.Function.CompatSpec (main, spec) where++import Test.Hspec+import Data.Function.Compat++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "&" $ do+ it "reverses function application" $ do+ (False & not) `shouldBe` True
+ test/Data/Functor/CompatSpec.hs view
@@ -0,0 +1,17 @@+module Data.Functor.CompatSpec (main, spec) where++import Test.Hspec+import Data.Functor.Compat++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "void" $ do+ it "discards computation result" $ do+ void (return 1 :: IO Int) `shouldReturn` ()++ describe "$>" $ do+ it "is the same as flipped <$" $ do+ (Just 5 :: Maybe Int) $> 6 `shouldBe` (Just 6 :: Maybe Int)
+ test/Data/IORef/CompatSpec.hs view
@@ -0,0 +1,22 @@+module Data.IORef.CompatSpec (main, spec) where++import Test.Hspec++import Control.Monad+import Data.IORef.Compat++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "modifyIORef'" $+ it "mutates the contents of an IORef strictly" $ do+ ref <- newIORef 0+ replicateM_ 1000000 $ modifyIORef' ref (+1)+ readIORef ref `shouldReturn` (1000000 :: Int)+ describe "atomicModifyIORef'" $+ it "atomically modifies the contents of an IORef strictly" $ do+ ref <- newIORef 0+ replicateM_ 1000000 . atomicModifyIORef' ref $ \n -> (n+1, ())+ readIORef ref `shouldReturn` (1000000 :: Int)
+ test/Data/List/CompatSpec.hs view
@@ -0,0 +1,43 @@+module Data.List.CompatSpec (main, spec) where++import Test.Hspec+import Data.List.Compat++data Asymmetric = A | B deriving Show++instance Eq Asymmetric where+ A == _ = True+ B == _ = False++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "dropWhileEnd" $ do+ it "drops the largest suffix of a list in which a predicate holds for all elements" $ do+ dropWhileEnd (== ' ') "foo " `shouldBe` "foo"+ dropWhileEnd (== ' ') "foo bar" `shouldBe` "foo bar"+ describe "isSubsequenceOf" $ do+ it "returns True if the first list is a subsequence of the second list" $ do+ isSubsequenceOf "GHC" "The Glorious Haskell Compiler" `shouldBe` True+ isSubsequenceOf "JHC" "The Glorious Haskell Compiler" `shouldBe` False+ describe "nub" $+ it "preserves the order of arguments to (==)" $+ nub [A, B] `shouldBe` [A]+ describe "nubBy" $+ it "preserves the order of arguments to the equality function" $+ nubBy (<) "12" `shouldBe` "1"+ describe "sortOn" $ do+ it "sorts a list by comparing the results of a key function applied to each element" $ do+ sortOn (>='b') "cba" `shouldBe` "acb"+ describe "uncons" $ do+ it "decomposes a list into its head and tail" $ do+ uncons "" `shouldBe` Nothing+ uncons "12" `shouldBe` Just ('1', "2")+ describe "union" $+ it "nubs arguments in the same order as (==)" $ do+ union [A] [A, B] `shouldBe` [A]+ describe "unionBy" $+ it "nubs arguments in the same order as nubBy's equality function" $ do+ unionBy (<) "1" "21" `shouldBe` "11"
+ test/Data/Monoid/CompatSpec.hs view
@@ -0,0 +1,16 @@+module Data.Monoid.CompatSpec (main, spec) where++import Test.Hspec+import Test.QuickCheck++import Data.Monoid.Compat++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "<>" $ do+ it "is an infix synonym for mappend" $ do+ property $ \xs ys -> do+ xs <> ys `shouldBe` (mappend xs ys :: String)
+ test/Data/STRef/CompatSpec.hs view
@@ -0,0 +1,19 @@+module Data.STRef.CompatSpec (main, spec) where++import Test.Hspec++import Control.Monad+import Control.Monad.ST+import Data.STRef.Compat++main :: IO ()+main = hspec spec++spec :: Spec+spec =+ describe "modifySTRef'" $+ it "should mutate the contents of an STRef strictly" $+ shouldBe (1000000 :: Int) $ runST $ do+ ref <- newSTRef 0+ replicateM_ 1000000 $ modifySTRef' ref (+1)+ readSTRef ref
+ test/Data/Version/CompatSpec.hs view
@@ -0,0 +1,10 @@+module Data.Version.CompatSpec (spec) where++import Test.Hspec+import Data.Version.Compat++spec :: Spec+spec = do+ describe "makeVersion" $+ it "constructs a tagless Version" $+ makeVersion [1,2,3] `shouldBe` Version [1,2,3] []
+ test/Data/Word/CompatSpec.hs view
@@ -0,0 +1,22 @@+module Data.Word.CompatSpec (main, spec) where++import Test.Hspec+import Data.Word.Compat++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "byteSwap16" $+ it "reverses the order of bytes in a Word16 value" $ do+ byteSwap16 0x1100 `shouldBe` 0x0011+ byteSwap16 0x1010 `shouldBe` 0x1010+ describe "byteSwap32" $+ it "reverses the order of bytes in a Word32 value" $ do+ byteSwap32 0x11001010 `shouldBe` 0x10100011+ byteSwap32 0x10101111 `shouldBe` 0x11111010+ describe "byteSwap64" $+ it "reverses the order of bytes in a Word64 value" $ do+ byteSwap64 0x1010111110101111 `shouldBe` 0x1111101011111010+ byteSwap64 0x1100000000000011 `shouldBe` 0x1100000000000011
+ test/Foreign/Marshal/Alloc/CompatSpec.hs view
@@ -0,0 +1,17 @@+module Foreign.Marshal.Alloc.CompatSpec (main, spec) where++import Test.Hspec++import Control.Exception+import Foreign.Marshal.Alloc.Compat+import Foreign.Storable++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "calloc" $+ it "allocates memory with bytes of value zero" $ do+ bracket calloc free $ \ptr -> do+ peek ptr `shouldReturn` (0 :: Int)
+ test/Foreign/Marshal/Utils/CompatSpec.hs view
@@ -0,0 +1,20 @@+module Foreign.Marshal.Utils.CompatSpec (main, spec) where++import Test.Hspec++import Foreign.Marshal.Alloc+import Foreign.Marshal.Utils.Compat+import Foreign.Ptr+import Foreign.Storable++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "fillBytes" $+ it "fills a given number of bytes in memory area with a byte value" $ do+ alloca $ \ptr -> do+ let _ = ptr :: Ptr Int+ fillBytes ptr 0 $ sizeOf ptr+ peek ptr `shouldReturn` 0
+ test/Numeric/CompatSpec.hs view
@@ -0,0 +1,24 @@+module Numeric.CompatSpec (main, spec) where++import Test.Hspec+import Numeric.Compat++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "showFFloatAlt" $ do+ it "shows a RealFloat value, always using decimal notation" $+ showFFloatAlt Nothing (12 :: Double) "" `shouldBe` "12.0"+ it "allows to specify the number of decimal places" $+ showFFloatAlt (Just 4) (12 :: Double) "" `shouldBe` "12.0000"+ describe "showGFloatAlt" $ do+ it "shows a RealFloat value, using decimal notation if the absolute value lies between 0.1 and 9,999,999" $+ showGFloatAlt Nothing (12 :: Double) "" `shouldBe` "12.0"+ it "shows a RealFloat value, using decimal notation and specifying the number of decimal places" $+ showGFloatAlt (Just 4) (12 :: Double) "" `shouldBe` "12.0000"+ it "shows a RealFloat value, using scientific notation if the absolute value falls outside of the range" $+ showGFloatAlt Nothing (1234567890 :: Double) "" `shouldBe` "1.23456789e9"+ it "shows a RealFloat value, using scientific notation and specifying the number of decimal places" $+ showGFloatAlt (Just 4) (1234567890 :: Double) "" `shouldBe` "1.2346e9"
+ test/System/Environment/CompatSpec.hs view
@@ -0,0 +1,120 @@+{-# LANGUAGE CPP #-}+module System.Environment.CompatSpec (main, spec) where++import Test.Hspec+import Test.QuickCheck++import qualified Control.Exception as E+import GHC.IO.Exception (IOErrorType (InvalidArgument))+import System.Environment.Compat+import System.IO.Error++main :: IO ()+main = hspec spec++withEnv :: String -> String -> IO a -> IO a+withEnv k v action = E.bracket save restore $ \_ -> do+ setEnv k v >> action+ where+ save = lookupEnv k+ restore = maybe (unsetEnv k) (setEnv k)++withoutEnv :: String -> IO a -> IO a+withoutEnv k action = E.bracket save restore $ \_ -> do+ unsetEnv k >> action+ where+ save = lookupEnv k+ restore = maybe (unsetEnv k) (setEnv k)++spec :: Spec+spec = do+ describe "lookupEnv" $ do+ it "returns specified environment variable" $ do+ withEnv "FOOBAR" "23" $ do+ lookupEnv "FOOBAR" `shouldReturn` Just "23"++ it "returns Nothing if specified environment variable is not set" $ do+ withoutEnv "FOOBAR" $ do+ lookupEnv "FOOBAR" `shouldReturn` Nothing++ describe "unsetEnv" $ do+ it "removes specified environment variable" $ do+ setEnv "FOO" "foo"+ unsetEnv "FOO"+ getEnv "FOO" `shouldThrow` isDoesNotExistError++ it "does nothing if specified environment variable is not set" $ do+ unsetEnv "BAR"+ unsetEnv "BAR"+ getEnv "BAR" `shouldThrow` isDoesNotExistError++ it "throws an exception if key is the empty string" $ do+ unsetEnv "" `shouldThrow` (== InvalidArgument) . ioeGetErrorType++ it "throws an exception if key contains '='" $ do+ unsetEnv "some=key" `shouldThrow` (== InvalidArgument) . ioeGetErrorType++ it "works for arbitrary keys" $+ property $ \k -> ('\NUL' `notElem` k && '=' `notElem` k && (not . null) k) ==> do+ setEnv k "foo"+ unsetEnv k+ getEnv k `shouldThrow` isDoesNotExistError++ describe "setEnv" $ do+ it "sets specified environment variable to given value" $ do+ unsetEnv "FOO"+ setEnv "FOO" "foo"+ getEnv "FOO" `shouldReturn` "foo"++ it "resets specified environment variable, if it is already set" $ do+ unsetEnv "FOO"+ setEnv "FOO" "foo"+ setEnv "FOO" "bar"+ getEnv "FOO" `shouldReturn` "bar"++ it "removes specified environment variable when value is the empty string" $ do+ setEnv "FOO" "foo"+ setEnv "FOO" ""+ getEnv "FOO" `shouldThrow` isDoesNotExistError++ it "removes specified environment variable when first character of value is NUL" $ do+ setEnv "FOO" "foo"+ setEnv "FOO" "\NULfoo"+ getEnv "FOO" `shouldThrow` isDoesNotExistError++ it "truncates value at NUL character" $ do+ unsetEnv "FOO"+ setEnv "FOO" "foo\NULbar"+ getEnv "FOO" `shouldReturn` "foo"++ it "truncates key at NUL character" $ do+ unsetEnv "FOO"+ setEnv "FOO\NULBAR" "foo"+ getEnv "FOO" `shouldReturn` "foo"++#if __GLASGOW_HASKELL__ >= 702+ it "works for unicode" $ do+ unsetEnv "FOO"+ setEnv "FOO" "foo-\955-bar"+ getEnv "FOO" `shouldReturn` "foo-\955-bar"+#endif++ it "works for arbitrary values" $+ property $ \v -> ('\NUL' `notElem` v && (not . null) v) ==> do+ setEnv "FOO" v+ getEnv "FOO" `shouldReturn` v++ it "works for unicode keys" $ do+ setEnv "foo-\955-bar" "foo"+ getEnv "foo-\955-bar" `shouldReturn` "foo"++ it "throws an exception if key is the empty string" $ do+ setEnv "" "foo" `shouldThrow` (== InvalidArgument) . ioeGetErrorType++ it "throws an exception if key contains '='" $ do+ setEnv "some=key" "foo" `shouldThrow` (== InvalidArgument) . ioeGetErrorType++ it "works for arbitrary keys" $+ property $ \k -> ('\NUL' `notElem` k && '=' `notElem` k && (not . null) k) ==> do+ setEnv k "foo"+ getEnv k `shouldReturn` "foo"
+ test/Text/Read/CompatSpec.hs view
@@ -0,0 +1,24 @@+module Text.Read.CompatSpec (main, spec) where++import Test.Hspec++import Text.Read.Compat++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "readMaybe" $ do+ it "parses a value" $ do+ readMaybe "23" `shouldBe` (Just 23 :: Maybe Int)++ it "returns Nothing if parsing fails" $ do+ readMaybe "xx" `shouldBe` (Nothing :: Maybe Int)++ describe "readEither" $ do+ it "parses a value" $ do+ readEither "23" `shouldBe` (Right 23 :: Either String Int)++ it "returns Left if parsing fails" $ do+ readEither "xx" `shouldBe` (Left "Prelude.read: no parse" :: Either String Int)