README.markdown
1# A compatibility layer for `base`
2[![Hackage](https://img.shields.io/hackage/v/base-compat.svg)][Hackage: base-compat]
3[![Hackage Dependencies](https://img.shields.io/hackage-deps/v/base-compat.svg)](http://packdeps.haskellers.com/reverse/base-compat)
4[![Haskell Programming Language](https://img.shields.io/badge/language-Haskell-blue.svg)][Haskell.org]
5[![BSD3 License](http://img.shields.io/badge/license-MIT-brightgreen.svg)][tl;dr Legal: MIT]
6
7[Hackage: base-compat]:
8 http://hackage.haskell.org/package/base-compat
9 "base-compat package on Hackage"
10[Haskell.org]:
11 http://www.haskell.org
12 "The Haskell Programming Language"
13[tl;dr Legal: MIT]:
14 https://tldrlegal.com/license/mit-license
15 "MIT License"
16
17## Scope
18
19The scope of `base-compat` is to provide functions available in later versions
20of base to a wider (older) range of compilers.
21
22In addition, successful library proposals that have been accepted to be part of
23upcoming versions of `base` are also included. This package is not intended to
24replace `base`, but to complement it.
25
26Note that `base-compat` does not add any orphan instances. There is a separate
27package [`base-orphans`](https://github.com/haskell-compat/base-orphans) for
28that.
29
30In addition, `base-compat` only backports functions. In particular, we
31purposefully do not backport data types or type classes introduced in newer
32versions of `base`. For more info, see the
33[Data types and type classes](#data-types-and-type-classes)
34section.
35
36`base-compat` is intentionally designed to have zero dependencies. As a
37consequence, there are some modules that can only be backported up to certain
38versions of `base`. If an even wider support window is desired in these
39scenarios, there also exists a `base-compat-batteries` package which augments
40`base-compat` with certain compatibility package dependencies. For more info,
41see the [Dependencies](#dependencies) section.
42
43## Basic usage
44
45In your cabal file, you should have something like this:
46
47```
48 build-depends: base >= 4.3
49 , base-compat >= 0.9.0
50```
51
52Then, lets say you want to use the `isRight` function introduced with
53`base-4.7.0.0`. Replace:
54
55```
56import Data.Either
57```
58
59with
60
61```
62import Data.Either.Compat
63```
64
65_Note (1)_: There is no need to import both unqualified. The `.Compat` modules
66re-exports the original module.
67
68_Note (2)_: If a given module `.Compat` version is not defined, that either
69means that:
70
71* The module has not changed in recent base versions, thus no `.Compat` is
72 needed.
73* The module has changed, but the changes depend on newer versions of GHC, and
74 thus are not portable.
75* The module has changed, but those changes have not yet been merged in
76 `base-compat`: patches are welcomed!
77
78## Using `Prelude.Compat`
79
80If you want to use `Prelude.Compat` (which provides all the
81AMP/Traversable/Foldable changes from `base-4.8.0.0`), it's best to hide
82`Prelude`, e.g.:
83
84 import Prelude ()
85 import Prelude.Compat
86
87 main :: IO ()
88 main = mapM_ print (Just 23)
89
90Alternatively, you can use the `NoImplicitPrelude` language extension:
91
92 {-# LANGUAGE NoImplicitPrelude #-}
93 import Prelude.Compat
94
95 main :: IO ()
96 main = mapM_ print (Just 23)
97
98Note that we use
99
100 mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m ()
101
102from `Data.Foldable` here, which is only exposed from `Prelude` since
103`base-4.8.0.0`.
104
105Using this approach allows you to write code that works seamlessly with all
106versions of GHC that are supported by `base-compat`.
107
108## What is covered
109So far the following is covered.
110
111### For compatibility with the latest released version of `base`
112
113 * `Prelude.Compat` incorporates the AMP/Foldable/Traversable changes and
114 exposes the same interface as `Prelude` from `base-4.9.0.0`
115 * `System.IO.Error.catch` is not re-exported from `Prelude.Compat` for older
116 versions of `base`
117 * `Text.Read.Compat.readMaybe`
118 * `Text.Read.Compat.readEither`
119 * `Data.Monoid.Compat.<>`
120 * Added `bitDefault`, `testBitDefault`, and `popCountDefault` to `Data.Bits.Compat`
121 * Added `toIntegralSized` to `Data.Bits.Compat` (if using `base-4.7`)
122 * Added `bool` function to `Data.Bool.Compat`
123 * Added `isLeft`, `isRight`, `fromLeft`, and `fromRight` to `Data.Either.Compat`
124 * Added `forkFinally` to `Control.Concurrent.Compat`
125 * Added `withMVarMasked` function to `Control.Concurrent.MVar.Compat`
126 * Added `(<$!>)` function to `Control.Monad.Compat`
127 * Weakened `RealFloat` constraints on `realPart`, `imagPart`, `conjugate`, `mkPolar`,
128 and `cis` in `Data.Complex.Compat`
129 * Added more efficient `maximumBy`/`minimumBy` to `Data.Foldable.Compat`
130 * Added `($>)` and `void` functions to `Data.Functor.Compat`
131 * `(&)` function to `Data.Function.Compat`
132 * `($>)` and `void` functions to `Data.Functor.Compat`
133 * `modifyIORef'`, `atomicModifyIORef'` and `atomicWriteIORef` to `Data.IORef.Compat`
134 * `dropWhileEnd`, `isSubsequenceOf`, `sortOn`, and `uncons` functions to `Data.List.Compat`
135 * Correct versions of `nub`, `nubBy`, `union`, and `unionBy` to `Data.List.Compat`
136 * `asProxyTypeOf` with a generalized type signature to `Data.Proxy.Compat`
137 * `modifySTRef'` to `Data.STRef.Compat`
138 * `String`, `lines`, `words`, `unlines`, and `unwords` to `Data.String.Compat`
139 * `gcoerceWith` to `Data.Type.Coercion.Compat`
140 * `makeVersion` function to `Data.Version.Compat`
141 * `traceId`, `traceShowId`, `traceM`, and `traceShowM` functions to `Debug.Trace.Compat`
142 * `byteSwap16`, `byteSwap32`, and `byteSwap64` to `Data.Word.Compat`
143 * `plusForeignPtr` to `Foreign.ForeignPtr.Compat`
144 * `calloc` and `callocBytes` functions to `Foreign.Marshal.Alloc.Compat`
145 * `callocArray` and `callocArray0` functions to `Foreign.Marshal.Array.Compat`
146 * `fillBytes` to `Foreign.Marshal.Utils.Compat`
147 * Added `Data.List.Compat.scanl'`
148 * `showFFloatAlt` and `showGFloatAlt` to `Numeric.Compat`
149 * `lookupEnv`, `setEnv` and `unsetEnv` to `System.Environment.Compat`
150 * `unsafeFixIO` and `unsafeDupablePerformIO` to `System.IO.Unsafe.IO`
151 * `RuntimeRep`-polymorphic `($!)` to `Prelude.Compat`
152 * `RuntimeRep`-polymorphic `throw` to `Control.Exception.Compat`
153 * `isResourceVanishedError`, `resourceVanishedErrorType`, and
154 `isResourceVanishedErrorType` to `System.IO.Error.Compat`
155 * `singleton` to `Data.List.Compat` and `Data.List.NonEmpty.Compat`
156 * `hGetContents'`, `getContents'`, and `readFile'` to `System.IO`
157
158## What is not covered
159
160### Data types and type classes
161`base-compat` purposefully does not export any data types or type classes that
162were introduced in more recent versions of `base`. The main reasoning for this
163policy is that it is not some data types and type classes have had their APIs
164change in different versions of `base`, which makes having a consistent
165compatibility API for them practically impossible.
166
167As an example, consider the `FiniteBits` type class. It was introduced in
168[`base-4.7.0.0`](http://hackage.haskell.org/package/base-4.7.0.0/docs/Data-Bits.html#t:FiniteBits)
169with the following API:
170
171```haskell
172class Bits b => FiniteBits b where
173 finiteBitSize :: b -> Int
174```
175
176However, in [`base-4.8.0.0`](http://hackage.haskell.org/package/base-4.8.0.0/docs/Data-Bits.html#t:FiniteBits),
177`FiniteBits` gained additional functions:
178
179```haskell
180class Bits b => FiniteBits b where
181 finiteBitSize :: b -> Int
182 countLeadingZeros :: b -> Int -- ^ @since 4.8.0.0
183 countTrailingZeros :: b -> Int -- ^ @since 4.8.0.0
184```
185
186This raises the question: how can `FiniteBits` be backported consistently
187across all versions of `base`? One approach is to backport the API exposed in
188`base-4.8.0.0` on versions prior to `4.7.0.0`. The problem with this is that
189`countLeadingZeros` and `countTrailingZeros` are not exposed in `base-4.7.0.0`,
190so instances of `FiniteBits` would have to be declared like this:
191
192```haskell
193instance FiniteBits Foo where
194 finiteBitSize = ...
195#if MIN_VERSION_base(4,8,0) || !(MIN_VERSION_base(4,7,0))
196 countLeadingZeros = ...
197 countTrailingZeros = ...
198#endif
199```
200
201Another approach is to backport the API from `base-4.7.0.0` and to declare
202additional methods outside of the class:
203
204```haskell
205#if MIN_VERSION_base(4,7,0) && !(MIN_VERSION_base(4,8,0))
206countLeadingZeros :: FiniteBits b => b -> Int
207countLeadingZeros = {- default implementation #-}
208#endif
209```
210
211The situation is only slightly better for classes which exist across all versions of `base`,
212but have grown their API. For example, it's tempting to define
213
214```haskell
215#if !(MIN_VERSION_base(4,8,0))
216displayException :: Exception e => e -> String
217displayException = show
218#endif
219```
220
221As with the previous approach, you won't be able to define new members of the type
222class without CPP guards. In other words, the non-CPP approach would limit
223uses to the lowest common denominator.
224
225As neither approach is a very satisfactory solution, and to embrace
226consistency, we do not pursue either approach. For similar reasons, we do not
227backport data types.
228
229### Dependencies
230
231`base-compat` is designed to have zero dependencies (besides libraries that
232ship with GHC itself). A consequence of this choice is that there are certain
233modules that have a "limited" support window. An important example of this is
234`Prelude.Compat`, which backports the `Semigroup` class to versions of `base`
235older than 4.11 (when it was added to the `Prelude`). Because `Semigroup` was
236not added to `base` until `base-4.9`, `base-compat` cannot backport it to
237any earlier version of `base` than this.
238
239If you would instead desire to be able to use a version of `Prelude.Compat`
240that _does_ backport `Semigroup` to even older versions of `base`, even if it
241means pulling in other dependencies, then you are in luck. There also exists
242a `base-compat-batteries` package, which exposes a strict superset of the API
243in `base-compat`. `base-compat-batteries` has all the same modules as
244`base-compat`, but exposes more functionality on more versions of `base` by
245reexporting things from compatibility libraries whenever necessary. (For
246instance, `base-compat-batteries` exports the `Semigroup` class from the
247`semigroups` library when built against versions of `base` older than 4.9.)
248
249Because `base-compat` and `base-compat-batteries` have the same module names,
250they are quite easy to switch out for one another in library projects, at the
251expense of having clashing names if one tries to import them in GHCi. To
252work around this issue, `base-compat` and `base-compat-batteries` also provide
253copies of each module with the suffix `.Repl` (for `base-compat`) and
254`.Repl.Batteries` (for `base-compat-batteries`) to give them globally unique
255namespaces in the event one wants to import them into GHCi.
256
257Here is a list of compatibility libraries that `base-compat-batteries` depends
258on, paired with the things that each library backports:
259
260* [`bifunctors`](http://hackage.haskell.org/package/bifunctors)
261 for:
262 * The [`Bifunctor`](http://hackage.haskell.org/package/base-4.8.0.0/docs/Data-Bifunctor.html#t:Bifunctor)
263 type class, introduced in `base-4.8.0.0`
264 * The [`Bifoldable`](http://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Bifoldable.html#t:Bifoldable)
265 and [`Bitraversable`](http://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Bitraversable.html#t:Bitraversable)
266 type classes, introduced in `base-4.10.0.0`
267* [`contravariant`](http://hackage.haskell.org/package/contravariant)
268 for the [`Contravariant`](http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Functor-Contravariant.html#t:Contravariant)
269 type class, introduced in `base-4.12.0.0`.
270* [`fail`](http://hackage.haskell.org/package/fail)
271 for the [`MonadFail`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Control-Monad-Fail.html#t:MonadFail)
272 type class, introduced in `base-4.9.0.0`
273* [`nats`](http://hackage.haskell.org/package/nats)
274 for the [`Natural`](http://hackage.haskell.org/package/base-4.8.0.0/docs/Numeric-Natural.html)
275 data type, introduced in `base-4.8.0.0`
276* [`semigroups`](http://hackage.haskell.org/package/semigroups)
277 for the [`Semigroup`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Semigroup)
278 typeclass and the
279 [`NonEmpty`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-List-NonEmpty.html#t:NonEmpty),
280 [`Min`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Min),
281 [`Max`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Max),
282 [`First`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:First),
283 [`Last`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Last),
284 [`WrappedMonoid`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:WrappedMonoid),
285 [`Option`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Option),
286 and
287 [`Arg`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Arg)
288 data types, introduced in `base-4.9.0.0`
289* [`tagged`](http://hackage.haskell.org/package/tagged)
290 for the [`Proxy`](http://hackage.haskell.org/package/base-4.7.0.0/docs/Data-Proxy.html#t:Proxy)
291 data type, introduced in `base-4.7.0.0`
292* [`transformers`](http://hackage.haskell.org/package/transformers)
293 for:
294 * The [`Identity`](http://hackage.haskell.org/package/base-4.8.0.0/docs/Data-Functor-Identity.html#t:Identity)
295 data type, introduced in `base-4.8.0.0`
296 * The [`MonadIO`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Control-Monad-IO-Class.html#t:MonadIO)
297 type class; and the
298 [`Compose`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Compose.html#t:Compose),
299 [`Product`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Product.html#t:Product),
300 and
301 [`Sum`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Sum.html#t:Sum)
302 data types, introduced in `base-4.9.0.0`
303* [`void`](http://hackage.haskell.org/package/void)
304 for the [`Void`](http://hackage.haskell.org/package/base-4.8.0.0/docs/Data-Void.html#t:Void)
305 data type, introduced in `base-4.8.0.0`
306
307## Supported versions of GHC/`base`
308
309 * `ghc-9.0.*` / `base-4.15.*`
310 * `ghc-8.10.*` / `base-4.14.*`
311 * `ghc-8.8.*` / `base-4.13.*`
312 * `ghc-8.6.*` / `base-4.12.*`
313 * `ghc-8.4.*` / `base-4.11.*`
314 * `ghc-8.2.*` / `base-4.10.*`
315 * `ghc-8.0.*` / `base-4.9.*`
316 * `ghc-7.10.*` / `base-4.8.*`
317 * `ghc-7.8.*` / `base-4.7.*`
318 * `ghc-7.6.*` / `base-4.6.*`
319 * `ghc-7.4.*` / `base-4.5.*`
320 * `ghc-7.2.*` / `base-4.4.*`
321 * `ghc-7.0.*` / `base-4.3.*`
322
323We also make an attempt to keep `base-compat` building with GHC HEAD, but due
324to its volatility, it may not work at any given point in time. If it doesn't,
325please report it!
326
327Patches are welcome; add tests for new code!
328