Better Haskell packages with hpack

by Taylor Fausak on

Writing a Haskell package requires putting the package metadata in a Cabal file. Unfortunately the Cabal file format is custom, tedious, and verbose. Simon Hengel’s hpack tool provides a better way to define Haskell packages. That’s why my Haskell package checklist recommends using hpack.

Cabal uses a custom file format. As far as I know, the only way to parse a Cabal file is with Haskell using the Cabal library. This makes them hard to use from other languages for routine editing, extracting information, or pretty printing. By comparison, hpack is just YAML. Chances are that you, your editor, and the other languages you use are already familiar with YAML.

Another problem with the Cabal file format is that it requires a lot of unnecessary boilerplate. For example, when you create a new module in your package, you have to add it to either the exposed-modules or other-modules. If you don’t, that module won’t be available and you’ll get strange linking errors. hpack automatically finds your modules and exposes them, but it still gives you control and the ability to hide certain modules.

In addition to removing boilerplate, hpack adds some nice shortcuts for common functionality. For instance, you may have a bunch of template files that need to be included with your package. With Cabal, you’d have to manually list them and remember to keep it up to date as you add and remove them. With hpack, you can say something like extra-source-files: templates/* and forget about it.

hpack also drastically reduces duplication. It’s very common for a package to define a library, an executable, and a test suite that all need the same dependencies. Cabal forces you to list these dependencies in each section, easily tripling the size of the package file. hpack lets you put your dependencies at the top level so they’re shared between the sections. (Cabal may eventually get similar functionality, but this has been a known problem since at least 2012.)

hpack provides all these nice-to-have features without restricting what you can configure. You’re not losing any power by switching from Cabal to hpack. In fact, it’s possible to mechanically convert a Cabal file into hpack with hpack-convert.

Stack has hpack built right in. So if you’re using Stack to build your package (and you probably should be) then you get hpack for free as part of stack build. And since hpack generates a Cabal file, it’s easy to go back to using Cabal if you need to do that for whatever reason.

In short, use hpack to make your life as a Haskell package author easier.