Home

Awesome

dhall-to-cabal - generate Cabal files from Dhall expression

dhall-to-cabal takes Dhall expressions and compiles them into Cabal files. All of the features of Dhall are supported, such as let bindings and imports, and all features of Cabal are supported (including conditional stanzas).

Getting Started

To get started with dhall-to-cabal, first install the dhall-to-cabal executable. This can be done using cabal:

cabal install dhall-to-cabal

(You may need to run cabal update first).

Next, write the Dhall expression that you would like to compile to a Cabal file. For some example Dhall files, see

To see the full schema supported by dhall-to-cabal, you can run dhall-to-cabal --print-type. (In the future, we will have more human-ready documentation - we'd love your help here!)

Once you have your Dhall file ready, point dhall-to-cabal at it:

dhall-to-cabal input.dhall

(Replace the name input.dhall with your actual input file).

That's it! dhall-to-cabal does the rest - it will figure out what the .cabal file should be called, and write it out next to the input.

If you'd rather put the file somewhere else, have a look at dhall-to-cabal --help and use one of the --output-* options.

cabal-to-dhall

Good news! dhall-to-cabal is currently running a two-for-one deal! By installing dhall-to-cabal we'll throw in the cabal-to-dhall executable absolutely free! cabal-to-dhall does the reverse of dhall-to-cabal - taking .cabal files and transforming them into appropriate Dhall expressions. This can be a great way to get started with dhall-to-cabal.

The Details

As the name suggests, dhall-to-cabal takes Dhall expressions and compiles them into Cabal files. There are two moving pieces here, so let's break it down.

Dhall?

Dhall is a relatively new language started by Gabriel Gonzales in late 2016. The language bills itself as "a configuration language guaranteed to terminate". In terms of features, we have a language with:

To give you an example of a Dhall expression, let's jump straight in and see an example of a Dhall expression that can be used with dhall-to-cabal:

let GitHub-project =
      https://raw.githubusercontent.com/dhall-lang/dhall-to-cabal/1.3.4.0/dhall/utils/GitHub-project.dhall

let prelude =
      https://raw.githubusercontent.com/dhall-lang/dhall-to-cabal/1.3.4.0/dhall/prelude.dhall

in    GitHub-project { owner = "ocharles", repo = "example" }
    ⫽ { version =
          prelude.v "1.0.0"
      , library =
          prelude.unconditional.library
          (   prelude.defaults.MainLibrary
            ⫽ { build-depends =
                  [ { package =
                        "base"
                    , bounds =
                        prelude.majorBoundVersion (prelude.v "4")
                    }
                  ]
              , exposed-modules =
                  [ "Hello.World" ]
              }
          )
      }

We can see quite a few features in use here. Ignoring what this file actually does (for now), let's focus on the language features.

At the start of we can see a few let bindings whose values themselves are imports over HTTP. Finally, we get into the body of the expression which is formed from two parts - function application of GitHub-project which is given a record as argument (with owner and repo Text fields), and another larger record. The result of GitHub-project and the library-containing record are then "merged" together using the operator. In this case, you can think of this as overriding or extending the result of GitHub-project with an extra library field.

It's OK if you don't follow all of the above - my goal is to simply get you familiar with what a Dhall expression would look like. The Dhall language itself has a much more detailed tutorial and other documentation.

Cabal?

Cabal is something that you might already be familiar with, but if you're not, Cabal is:

a system for building and packaging Haskell libraries and programs. It defines a common interface for package authors and distributors to easily build their applications in a portable way. Cabal is part of a larger infrastructure for distributing, organizing, and cataloging Haskell libraries and programs.

(taken from the Cabal homepage).

Almost all Haskell libraries are built using some parts of the Cabal system.

For the purposes of this project, we're interested in .cabal files themselves. Cabal is a build-system, but it's also a domain specific language for driving this build system.

A small example Cabal file is

cabal-version: 2.2
name: example
version: 1.0.0
homepage: https://github.com/ocharles/example
bug-reports: https://github.com/ocharles/example/issues

source-repository head
    type: git
    location: https://github.com/ocharles/example

library
    exposed-modules:
        Hello.World
    build-depends:
        base ^>=4

In this, we see some leading metadata about the Haskell package itself - the name of the package, its homepage and its license, and so on. Towards the end of the file, we add a library component to the package. To build this library, we depend on the base library (which contains the standard Haskell prelude) and will expose the Hello.World module as our API.

dhall-to-cabal?

dhall-to-cabal tries to bridge the gap between these two separate worlds by allowing users to drive the Cabal build system via Dhall expressions. If you hadn't noticed by now, you've already seen an input Dhall-to-Cabal expression, and you've also already seen the corresponding output!

Getting Started

You can get dhall-to-cabal from Hackage. For usage, run dhall-to-cabal --help. For some example Dhall expressions, see dhall-to-cabal.dhall, lens.dhall or str-sig.dhall. These are all fairly big expressions to test the project itself... if you have a simpler example that you think would act as good reference, that would make a great starting pull request!

Why?

I wrote dhall-to-cabal for a few reasons. Firstly, let's start with the self-centered arguments:

These are enough for me to justify the work, but it doesn't necessarily imply that the project is of value. However, I think there is some value in this project.