Overture: A Haskell Prelude
The majority of our backend work at Helium is written in Haskell. Haskell is a terrific language, but it shows its age at times. (Not many people realize that Haskell is older than Java.) And perhaps its most noticeable sign of age is its Prelude — the set of built-in functions and data types provided by default in every Haskell program.
There have been many other ambitious replacement Preludes. classy-prelude generalizes nearly every Prelude function, depending on the mono-traversable package to provide a unified information between standard and monomorphic containers. yap provides a new set of algebraic and numerical classes derived from abstract algebra. foundation is a new and ambitious retooling of nearly every core Haskell datatype, with an additional compatibility layer to provide interoperation with packages from the library ecosystem.
We at Helium quickly grew tired of the limits of the Haskell 98 Prelude, but none of the existing solutions fit our needs exactly. We needed something that fit all the following criteria:
1. It needed to be a drop-in replacement for the Haskell 98 Prelude. The ambitious, backwards-incompatible Preludes have a great many terrific ideas, but we don’t have the time or inclination to rework our existing code to conform to an entirely-new set of idioms.
2. It needed to provide access to the most-commonly used datatypes from the Haskell ecosystem. The effort to depend only on the primitives provided by the base package is noble, but in practice nearly every module we write depends on Text and ByteString values. Monad transfomers are nearly-ubiquitous in practice, so we pull in Control.Monad.Trans from the mtl library. While there’s no need to pull in every conceivable aspect of Haskell’s library ecosystem, there are a few packages that are used just about everywhere, and our solution needed to provide access to these packages for sanity’s sake.
3. It needed to generalize every exported function to the greatest extent possible. The Foldable-Traversable proposal generalized a great many of Haskell’s built-in functions, much to our relief. But there are still many other functions that call out for generalized versions: for example: the base package’s error-handling functions are limited to operating in the IO monad. The lifted-base package provides more powerful versions that operate in any monad stack that supports IO computations.
4. It needed to work well in tandem with Control.Lens. Not everyone in the Haskell community uses the lens library — but we at Helium do, and we’ve come to rely on its incredible power and concision. Control.Lens exports a whole lot of identifiers, and we needed to ensure that our solution didn’t conflict with the common lens identifiers.
None of the existing preludes in the ecosystem met all these criteria, so we built our own. We’ve been using this generalized Prelude, dubbed Overture (get it?!) in production for more than a year at this point. It saves us many hundreds of unnecessary import statements throughout our code. To get started, merely just add helium-overture to your cabal file, and drop in an `import Overture` at the beginning of your Haskell files-then proceed to remove the dozens of imports that Overture takes care of for you.
We’re pleased to be able to open-source Overture on GitHub. Because it is so colossally simple — just under a hundred lines of aggregated import statements — we’re offering it under the no-rights-reserved Unlicense: please, do whatever you want with it. (Contributions back are always welcome!)
Custom Haskell Preludes are often viewed with some skepticism by the community. We hope that Overture shows that custom preludes don’t have to reinvent every wheel: they can be a simple, useful part of your daily workflow.