# A compatibility layer for `base`

## Scope

The scope of `base-compat`

is to provide functions available in later versions
of base to a wider (older) range of compilers.

In addition, successful library proposals that have been accepted to be part of
upcoming versions of `base`

are also included. This package is not intended to
replace `base`

, but to complement it.

Note that `base-compat`

does not add any orphan instances. There is a separate
package `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
section.

## Basic usage

In your cabal file, you should have something like this:

```
build-depends: base >= 4.3
, base-compat >= 0.9.0
```

Then, lets say you want to use the `isRight`

function introduced with
`base-4.7.0.0`

. Replace:

```
import Data.Either
```

with

```
import Data.Either.Compat
```

*Note (1)*: There is no need to import both unqualified. The `.Compat`

modules
re-exports the original module.

*Note (2)*: If a given module `.Compat`

version is not defined, that either
means that:

- The module has not changed in recent base versions, thus no
`.Compat`

is
needed.
- The module has changed, but the changes depend on newer versions of GHC, and
thus are not portable.
- The module has changed, but those changes have not yet been merged in
`base-compat`

: patches are welcomed!

## Using `Prelude.Compat`

If you want to use `Prelude.Compat`

(which provides all the
AMP/Traversable/Foldable changes from `base-4.8.0.0`

), it's best to hide
`Prelude`

, e.g.:

```
import Prelude ()
import Prelude.Compat
main :: IO ()
main = mapM_ print (Just 23)
```

Alternatively, you can use the `NoImplicitPrelude`

language extension:

```
{-# LANGUAGE NoImplicitPrelude #-}
import Prelude.Compat
main :: IO ()
main = mapM_ print (Just 23)
```

Note that we use

```
mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m ()
```

from `Data.Foldable`

here, which is only exposed from `Prelude`

since
`base-4.8.0.0`

.

Using this approach allows you to write code that works seamlessly with all
versions of GHC that are supported by `base-compat`

.

## What is covered

So far the following is covered.

### 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.9.0.0`

`System.IO.Error.catch`

is not re-exported from `Prelude.Compat`

for older
versions of `base`

`Text.Read.Compat.readMaybe`

`Text.Read.Compat.readEither`

`Data.Monoid.Compat.<>`

- Added
`bitDefault`

, `testBitDefault`

, and `popCountDefault`

to `Data.Bits.Compat`

- Added
`toIntegralSized`

to `Data.Bits.Compat`

(if using `base-4.7`

)
- Added
`bool`

function to `Data.Bool.Compat`

- Added
`isLeft`

, `isRight`

, `fromLeft`

, and `fromRight`

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 more efficient
`maximumBy`

/`minimumBy`

to `Data.Foldable.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`

`asProxyTypeOf`

with a generalized type signature to `Data.Proxy.Compat`

`modifySTRef'`

to `Data.STRef.Compat`

`String`

, `lines`

, `words`

, `unlines`

, and `unwords`

to `Data.String.Compat`

`gcoerceWith`

to `Data.Type.Coercion.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`

`plusForeignPtr`

to `Foreign.ForeignPtr.Compat`

`calloc`

and `callocBytes`

functions to `Foreign.Marshal.Alloc.Compat`

`callocArray`

and `callocArray0`

functions to `Foreign.Marshal.Array.Compat`

`fillBytes`

to `Foreign.Marshal.Utils.Compat`

- 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`

## 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`

with the following API:

```
class Bits b => FiniteBits b where
finiteBitSize :: b -> Int
```

However, in `base-4.8.0.0`

,
`FiniteBits`

gained additional functions:

```
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:

```
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`

for:
`fail`

for the `MonadFail`

type class, introduced in `base-4.9.0.0`

`generic-deriving`

for everything in the `GHC.Generics`

module, introduced to `ghc-prim`

in GHC 7.2 (and later moved to `base-4.6.0.0`

)
`nats`

for the `Natural`

data type, introduced in `base-4.8.0.0`

`semigroups`

for the `Semigroup`

typeclass and the
`NonEmpty`

,
`Min`

,
`Max`

,
`First`

,
`Last`

,
`WrappedMonoid`

,
`Option`

,
and
`Arg`

data types, introduced in `base-4.9.0.0`

`tagged`

for the `Proxy`

data type, introduced in `base-4.7.0.0`

`transformers`

for:
- The
`Identity`

data type, introduced in `base-4.8.0.0`

- The
`MonadIO`

,
`Eq1`

,
`Eq2`

,
`Ord1`

,
`Ord2`

,
`Read1`

,
`Read2`

,
`Show1`

,
and
`Show2`

typeclasses; and the
`Compose`

,
`Product`

,
and
`Sum`

data types, introduced in `base-4.9.0.0`

`void`

for the `Void`

data type, introduced in `base-4.8.0.0`

## Supported versions of GHC/`base`

`ghc-8.2.1`

/ `base-4.10.0.0`

`ghc-8.0.2`

/ `base-4.9.1.0`

`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`

`ghc-7.8.2`

/ `base-4.7.0.0`

`ghc-7.8.1`

/ `base-4.7.0.0`

`ghc-7.6.3`

/ `base-4.6.0.1`

`ghc-7.6.2`

/ `base-4.6.0.1`

`ghc-7.6.1`

/ `base-4.6.0.0`

`ghc-7.4.2`

/ `base-4.5.1.0`

`ghc-7.4.1`

/ `base-4.5.0.0`

`ghc-7.2.2`

/ `base-4.4.1.0`

`ghc-7.2.1`

/ `base-4.4.0.0`

`ghc-7.0.4`

/ `base-4.3.1.0`

`ghc-7.0.3`

/ `base-4.3.1.0`

`ghc-7.0.2`

/ `base-4.3.1.0`

`ghc-7.0.1`

/ `base-4.3.0.0`

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!

Patches are welcome; add tests for new code!