diff --git a/Changelog.md b/Changelog.md
new file mode 100644
--- /dev/null
+++ b/Changelog.md
@@ -0,0 +1,5 @@
+# dhall-to-cabal change log
+
+## 1.0.0 -- 2018-03-23
+
+First release!
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Oliver Charles
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/cabal-to-dhall/Main.hs b/cabal-to-dhall/Main.hs
new file mode 100644
--- /dev/null
+++ b/cabal-to-dhall/Main.hs
@@ -0,0 +1,1345 @@
+{-# language FlexibleInstances #-}
+{-# language GeneralizedNewtypeDeriving #-}
+{-# language LambdaCase #-}
+{-# language NamedFieldPuns #-}
+{-# language OverloadedStrings #-}
+{-# language ViewPatterns #-}
+
+module Main ( main ) where
+
+import Control.Applicative ( (<**>), optional )
+import Control.Monad ( join )
+import Data.Foldable ( foldMap )
+import Data.Functor.Contravariant ( (>$<), Contravariant( contramap ) )
+import Data.Hashable ( Hashable )
+import Data.List ( sortBy )
+import Data.Maybe ( listToMaybe )
+import Data.Monoid ( First(..), (<>) )
+import Data.Ord ( comparing )
+import GHC.Stack
+import Numeric.Natural ( Natural )
+
+import qualified Data.HashMap.Strict.InsOrd as Map
+import qualified Data.Text.Lazy as LazyText
+import qualified Data.Text.Lazy.IO as LazyText
+import qualified Dhall
+import qualified Dhall.Core
+import qualified Dhall.Core as Expr ( Const(..), Expr(..) )
+import qualified Dhall.Import
+import qualified Dhall.Parser
+import qualified Dhall.TypeCheck
+import qualified Distribution.Compiler as Cabal
+import qualified Distribution.License as Cabal
+import qualified Distribution.ModuleName as Cabal
+import qualified Distribution.PackageDescription.Parse as Cabal
+import qualified Distribution.System as Cabal
+import qualified Distribution.Text as Cabal
+import qualified Distribution.Types.Benchmark as Cabal
+import qualified Distribution.Types.BenchmarkInterface as Cabal
+import qualified Distribution.Types.BuildInfo as Cabal
+import qualified Distribution.Types.BuildType as Cabal
+import qualified Distribution.Types.CondTree as Cabal
+import qualified Distribution.Types.Condition as Cabal
+import qualified Distribution.Types.Dependency as Cabal
+import qualified Distribution.Types.ExeDependency as Cabal
+import qualified Distribution.Types.Executable as Cabal
+import qualified Distribution.Types.ExecutableScope as Cabal
+import qualified Distribution.Types.ForeignLib as Cabal
+import qualified Distribution.Types.ForeignLibOption as Cabal
+import qualified Distribution.Types.ForeignLibType as Cabal
+import qualified Distribution.Types.GenericPackageDescription as Cabal
+import qualified Distribution.Types.IncludeRenaming as Cabal
+import qualified Distribution.Types.LegacyExeDependency as Cabal
+import qualified Distribution.Types.Library as Cabal
+import qualified Distribution.Types.Mixin as Cabal
+import qualified Distribution.Types.ModuleReexport as Cabal
+import qualified Distribution.Types.ModuleRenaming as Cabal
+import qualified Distribution.Types.PackageDescription as Cabal
+import qualified Distribution.Types.PackageId as Cabal
+import qualified Distribution.Types.PackageName as Cabal
+import qualified Distribution.Types.PkgconfigDependency as Cabal
+import qualified Distribution.Types.PkgconfigName as Cabal
+import qualified Distribution.Types.SetupBuildInfo as Cabal
+import qualified Distribution.Types.SourceRepo as Cabal
+import qualified Distribution.Types.TestSuite as Cabal
+import qualified Distribution.Types.TestSuiteInterface as Cabal
+import qualified Distribution.Types.UnqualComponentName as Cabal
+import qualified Distribution.Version as Cabal
+import qualified Language.Haskell.Extension as Cabal
+import qualified Options.Applicative as OptParse
+
+import DhallToCabal ( sortExpr )
+
+import qualified DhallToCabal
+
+
+preludeLocation :: Dhall.Core.Path
+preludeLocation =
+  Dhall.Core.Path
+    { Dhall.Core.pathHashed =
+        Dhall.Core.PathHashed
+          { Dhall.Core.hash =
+              Nothing
+          , Dhall.Core.pathType =
+              Dhall.Core.URL
+                "https://raw.githubusercontent.com/dhall-lang/dhall-to-cabal/1.0.0/dhall/prelude.dhall"
+                Nothing
+          }
+    , Dhall.Core.pathMode =
+        Dhall.Core.Code
+    }
+
+
+typesLocation :: Dhall.Core.Path
+typesLocation =
+  Dhall.Core.Path
+    { Dhall.Core.pathHashed =
+        Dhall.Core.PathHashed
+          { Dhall.Core.hash =
+              Nothing
+          , Dhall.Core.pathType =
+              Dhall.Core.URL
+                "https://raw.githubusercontent.com/dhall-lang/dhall-to-cabal/1.0.0/dhall/types.dhall"
+                Nothing
+          }
+    , Dhall.Core.pathMode =
+        Dhall.Core.Code
+    }
+
+
+type DhallExpr =
+  Dhall.Core.Expr Dhall.Parser.Src Dhall.TypeCheck.X
+
+
+data Command
+  = RunCabalToDhall CabalToDhallOptions
+
+
+data CabalToDhallOptions = CabalToDhallOptions
+  { cabalFilePath :: Maybe String
+  }
+
+
+cabalToDhallOptionsParser :: OptParse.Parser CabalToDhallOptions
+cabalToDhallOptionsParser =
+  CabalToDhallOptions
+    <$>
+      optional
+        ( OptParse.argument
+            OptParse.str
+            ( mconcat
+                [ OptParse.metavar "<cabal input file>"
+                , OptParse.help "The Cabal file to convert to Dhall"
+                ]
+            )
+        )
+
+
+commandLineParser =
+  RunCabalToDhall <$> ( cabalToDhallOptionsParser <**> OptParse.helper )
+
+
+main :: IO ()
+main = do
+  command <-
+    OptParse.execParser
+      ( OptParse.info commandLineParser mempty )
+
+  case command of
+    RunCabalToDhall options ->
+      runCabalToDhall options
+
+
+runCabalToDhall :: CabalToDhallOptions -> IO ()
+runCabalToDhall CabalToDhallOptions{ cabalFilePath } = do
+  source <-
+    case cabalFilePath of
+      Nothing ->
+        LazyText.getContents
+
+      Just filePath ->
+        LazyText.readFile filePath
+
+  case Cabal.parseGenericPackageDescription ( LazyText.unpack source ) of
+    Cabal.ParseFailed e -> do
+      putStrLn "Could not parse Cabal file: "
+
+      error ( show e )
+
+    Cabal.ParseOk _warnings genericPackageDescription -> do
+      let
+        dhall =
+          Expr.Let "prelude" Nothing ( Expr.Embed preludeLocation )
+            $ Expr.Let "types" Nothing ( Expr.Embed typesLocation )
+            $ ( Dhall.TypeCheck.absurd <$>
+                Dhall.embed
+                  genericPackageDescriptionToDhall
+                  genericPackageDescription
+              )
+
+      LazyText.putStrLn ( Dhall.Core.pretty dhall )
+
+
+newtype RecordInputType a =
+  RecordInputType
+    { unRecordInputType ::
+        Map.InsOrdHashMap Dhall.Text ( Dhall.InputType a )
+    }
+  deriving ( Monoid )
+
+
+instance Contravariant RecordInputType where
+  contramap f ( RecordInputType map ) =
+    RecordInputType ( fmap ( contramap f ) map )
+
+
+recordField :: Dhall.Text -> Dhall.InputType a -> RecordInputType a
+recordField k v =
+  RecordInputType ( Map.singleton k v )
+
+
+runRecordInputType :: RecordInputType a -> Dhall.InputType a
+runRecordInputType ( RecordInputType m ) =
+  Dhall.InputType
+    { Dhall.embed =
+        \a -> sortExpr ( Expr.RecordLit ( fmap ( \t -> Dhall.embed t a ) m ) )
+    , Dhall.declared = sortExpr ( Expr.Record ( fmap Dhall.declared m ) )
+    }
+
+
+genericPackageDescriptionToDhall
+  :: Dhall.InputType Cabal.GenericPackageDescription
+genericPackageDescriptionToDhall =
+  let
+    named k v =
+      listOf
+        ( runRecordInputType
+            ( mconcat
+                [ fst >$< recordField "name" unqualComponentName
+                , snd >$< recordField k v
+                ]
+            )
+        )
+
+  in
+  runRecordInputType
+    ( mconcat
+        [ Cabal.packageDescription >$< packageDescriptionToRecord
+        , recordField "flags" ( Cabal.genPackageFlags >$< ( listOf flag ) )
+        , recordField "library" ( Cabal.condLibrary >$< maybeToDhall ( condTree library ) )
+        , recordField "sub-libraries" ( Cabal.condSubLibraries >$< named "library" ( condTree library ) )
+        , recordField "foreign-libraries" ( Cabal.condForeignLibs >$< named "foreign-lib" ( condTree foreignLibrary ) )
+        , recordField "executables" ( Cabal.condExecutables >$< named "executable" ( condTree executable ) )
+        , recordField "test-suites" ( Cabal.condTestSuites >$< named "test-suite" ( condTree testSuite ) )
+        , recordField "benchmarks" ( Cabal.condBenchmarks >$< named "benchmark" ( condTree benchmark ) )
+        ]
+    )
+
+
+packageDescriptionToRecord
+  :: RecordInputType Cabal.PackageDescription
+packageDescriptionToRecord =
+  mconcat
+    [ contramap Cabal.package packageIdentifierToRecord
+    , recordField "source-repos" ( contramap Cabal.sourceRepos ( listOf sourceRepo ) )
+    , recordField "cabal-version" ( contramap Cabal.specVersionRaw specVersion )
+    , recordField "build-type" ( contramap Cabal.buildType ( maybeToDhall buildType ) )
+    , recordField "license" ( contramap Cabal.license licenseToDhall )
+    , recordField "license-files" ( contramap Cabal.licenseFiles ( listOf stringToDhall ) )
+    , recordField "copyright" ( contramap Cabal.copyright stringToDhall )
+    , recordField "maintainer" ( contramap Cabal.maintainer stringToDhall )
+    , recordField "author" ( contramap Cabal.author stringToDhall )
+    , recordField "stability" ( contramap Cabal.stability stringToDhall )
+    , recordField "tested-with" ( contramap Cabal.testedWith ( listOf compiler ) )
+    , recordField "homepage" ( contramap Cabal.homepage stringToDhall )
+    , recordField "package-url" ( contramap Cabal.pkgUrl stringToDhall )
+    , recordField "bug-reports" ( contramap Cabal.bugReports stringToDhall )
+    , recordField "synopsis" ( contramap Cabal.synopsis stringToDhall )
+    , recordField "description" ( contramap Cabal.description stringToDhall )
+    , recordField "category" ( contramap Cabal.category stringToDhall )
+    , recordField "custom-setup" ( contramap Cabal.setupBuildInfo ( maybeToDhall setupBuildInfo ) )
+    , recordField "data-files" ( contramap Cabal.dataFiles ( listOf stringToDhall ) )
+    , recordField "data-dir" ( contramap Cabal.dataDir stringToDhall )
+    , recordField "extra-source-files" ( contramap Cabal.extraSrcFiles ( listOf stringToDhall ) )
+    , recordField "extra-tmp-files" ( contramap Cabal.extraTmpFiles ( listOf stringToDhall ) )
+    , recordField "extra-doc-files" ( contramap Cabal.extraDocFiles ( listOf stringToDhall ) )
+    , recordField
+        "x-fields"
+        ( Cabal.customFieldsPD
+            >$<
+              listOf
+                ( runRecordInputType
+                    ( mconcat
+                        [ fst >$< recordField "_1" stringToDhall
+                        , snd >$< recordField "_2" stringToDhall
+                        ]
+                    )
+                )
+        )
+    ]
+
+
+packageIdentifierToRecord
+  :: RecordInputType Cabal.PackageIdentifier
+packageIdentifierToRecord =
+  mconcat
+    [ recordField "name" ( contramap Cabal.pkgName packageNameToDhall )
+    , recordField "version" ( contramap Cabal.pkgVersion versionToDhall )
+    ]
+
+
+packageNameToDhall :: Dhall.InputType Cabal.PackageName
+packageNameToDhall =
+  contramap Cabal.unPackageName stringToDhall
+
+
+versionToDhall :: Dhall.InputType Cabal.Version
+versionToDhall =
+  Dhall.InputType
+    { Dhall.embed =
+        Expr.App ( Expr.Var "prelude" `Expr.Field` "v" )
+          . Dhall.embed stringToDhall
+          . show
+          . Cabal.disp
+    , Dhall.declared =
+        Expr.Var "types" `Expr.Field` "Version"
+    }
+
+
+stringToDhall :: Dhall.InputType String
+stringToDhall =
+  contramap LazyText.pack Dhall.inject
+
+
+licenseToDhall :: Dhall.InputType Cabal.License
+licenseToDhall =
+  ( runUnion
+      ( mconcat
+          [ gpl
+          , agpl
+          , lgpl
+          , bsd2
+          , bsd3
+          , bsd4
+          , mit
+          , isc
+          , mpl
+          , apache
+          , publicDomain
+          , allRightsReserved
+          , unspecified
+          , other
+          -- , unknown
+          ]
+      )
+  )
+    { Dhall.declared =
+        Expr.Var "types" `Expr.Field` "License"
+    }
+
+  where
+
+    gpl =
+      unionAlt "GPL" ( \l -> case l of Cabal.GPL v -> Just v; _ -> Nothing ) ( maybeToDhall versionToDhall )
+
+    agpl =
+      unionAlt "AGPL" ( \l -> case l of Cabal.AGPL v -> Just v ; _ -> Nothing ) ( maybeToDhall versionToDhall )
+
+    lgpl =
+      unionAlt "LGPL" ( \l -> case l of Cabal.LGPL v -> Just v ; _ -> Nothing ) ( maybeToDhall versionToDhall )
+
+    bsd2 =
+      unionAlt "BSD2" ( \l -> case l of Cabal.BSD2 -> Just () ; _ -> Nothing ) Dhall.inject
+
+    bsd3 =
+      unionAlt "BSD3" ( \l -> case l of Cabal.BSD3 -> Just () ; _ -> Nothing ) Dhall.inject
+
+    bsd4 =
+      unionAlt "BSD4" ( \l -> case l of Cabal.BSD4 -> Just () ; _ -> Nothing ) Dhall.inject
+
+    mit =
+      unionAlt "MIT" ( \l -> case l of Cabal.MIT -> Just () ; _ -> Nothing ) Dhall.inject
+
+    isc =
+      unionAlt "ISC" ( \l -> case l of Cabal.ISC -> Just () ; _ -> Nothing ) Dhall.inject
+
+    mpl =
+      unionAlt "MPL" ( \l -> case l of Cabal.MPL v -> Just v ; _ -> Nothing ) versionToDhall
+
+    apache =
+      unionAlt "Apache" ( \l -> case l of Cabal.Apache v -> Just v ; _ -> Nothing ) ( maybeToDhall versionToDhall )
+
+    publicDomain =
+      unionAlt "PublicDomain" ( \l -> case l of Cabal.PublicDomain -> Just () ; _ -> Nothing ) Dhall.inject
+
+    allRightsReserved =
+      unionAlt "AllRightsReserved" ( \l -> case l of Cabal.AllRightsReserved -> Just () ; _ -> Nothing ) Dhall.inject
+
+    unspecified =
+      unionAlt
+        "Unspecified"
+        ( \l ->
+            case l of
+              Cabal.UnspecifiedLicense ->
+                Just ()
+
+              Cabal.UnknownLicense "UnspecifiedLicense" ->
+                Just ()
+
+              _ ->
+                Nothing
+        )
+        Dhall.inject
+
+    other =
+      unionAlt "Other" ( \l -> case l of Cabal.OtherLicense -> Just () ; _ -> Nothing ) Dhall.inject
+
+    unknown =
+      unionAlt "Unknown" ( \l -> case l of Cabal.UnknownLicense s -> Just s ; _ -> Nothing ) stringToDhall
+
+
+newtype Union a =
+  Union
+    { unUnion ::
+        ( a ->
+          ( First ( Dhall.Text, DhallExpr )
+          , Map.InsOrdHashMap Dhall.Text DhallExpr
+          )
+        , Map.InsOrdHashMap Dhall.Text DhallExpr
+        )
+    }
+  deriving ( Monoid )
+
+
+runUnion :: ( HasCallStack, Show a ) => Union a -> Dhall.InputType a
+runUnion ( Union ( f, t ) ) =
+  Dhall.InputType
+    { Dhall.embed =
+        \a ->
+          case f a of
+            ( First Nothing, _ ) ->
+              error $ "Union did not match anything. Given " ++ show a
+
+            ( First ( Just ( k, v ) ), alts ) ->
+              Expr.UnionLit k v alts
+    , Dhall.declared =
+        sortExpr ( Expr.Union t )
+    }
+
+
+unionAlt :: Dhall.Text -> ( a -> Maybe b ) -> Dhall.InputType b -> Union a
+unionAlt k f t =
+  Union
+    ( \a ->
+        case f a of
+          Nothing ->
+            ( mempty, Map.singleton k ( Dhall.declared t ) )
+
+          Just b ->
+            ( First ( fmap ( \b -> ( k, Dhall.embed t b ) ) ( f a ) ), mempty )
+    , Map.singleton k ( Dhall.declared t )
+    )
+
+
+maybeToDhall :: Dhall.InputType a -> Dhall.InputType ( Maybe a )
+maybeToDhall t =
+  Dhall.InputType
+    { Dhall.embed =
+        \a -> Expr.OptionalLit ( Dhall.declared t ) ( Dhall.embed t <$> a )
+    , Dhall.declared = Expr.App Expr.Optional ( Dhall.declared t )
+    }
+
+
+listOf :: Dhall.InputType a -> Dhall.InputType [ a ]
+listOf t =
+  Dhall.InputType
+    { Dhall.embed =
+        \a ->
+          Expr.ListLit
+            ( foldl ( \_ _ -> Nothing ) ( Just ( Dhall.declared t ) ) a )
+            ( foldMap ( pure . Dhall.embed t ) a )
+    , Dhall.declared = Expr.App Expr.List ( Dhall.declared t )
+    }
+
+
+compiler :: Dhall.InputType ( Cabal.CompilerFlavor, Cabal.VersionRange )
+compiler =
+  runRecordInputType
+    ( mconcat
+        [ recordField "compiler" ( contramap fst compilerFlavor )
+        , recordField "version" ( contramap snd versionRange )
+        ]
+    )
+
+
+instance {-# OVERLAPS #-} Dhall.Inject [Char] where
+  injectWith _ = stringToDhall
+
+instance Dhall.Inject Cabal.CompilerFlavor
+
+
+compilerFlavor :: Dhall.InputType Cabal.CompilerFlavor
+compilerFlavor =
+  let
+    constructor k v =
+      Expr.App ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "Compilers" `Expr.Field` k ) v
+
+  in
+  Dhall.InputType
+    { Dhall.embed = \case
+        Cabal.GHC ->
+          constructor "GHC" ( Expr.RecordLit mempty )
+
+        Cabal.GHCJS ->
+          constructor "GHCJS" ( Expr.RecordLit mempty )
+
+        Cabal.HBC ->
+          constructor "HBC" ( Expr.RecordLit mempty )
+
+        Cabal.HaskellSuite v ->
+          constructor "HaskellSuite" ( Expr.Record ( Map.singleton "_1" ( Dhall.embed Dhall.inject v ) ) )
+
+        Cabal.Helium ->
+          constructor "Helium" ( Expr.RecordLit mempty )
+
+        Cabal.Hugs ->
+          constructor "Hugs" ( Expr.RecordLit mempty )
+
+        Cabal.JHC ->
+          constructor "JHC" ( Expr.RecordLit mempty )
+
+        Cabal.LHC ->
+          constructor "LHC" ( Expr.RecordLit mempty )
+
+        Cabal.NHC ->
+          constructor "NHC" ( Expr.RecordLit mempty )
+
+        Cabal.OtherCompiler v ->
+          constructor "OtherCompiler" ( Expr.Record ( Map.singleton "_1" ( Dhall.embed Dhall.inject v ) ) )
+
+        Cabal.UHC ->
+          constructor "UHC" ( Expr.RecordLit mempty )
+
+        Cabal.YHC ->
+          constructor "YHC" ( Expr.RecordLit mempty )
+    , Dhall.declared =
+        Expr.Var "types" `Expr.Field` "Compiler"
+    }
+
+
+versionRange :: Dhall.InputType Cabal.VersionRange
+versionRange =
+  Dhall.InputType
+    { Dhall.embed =
+        \versionRange0 ->
+          let
+            go versionRange =
+              case versionRange of
+                Cabal.AnyVersion ->
+                  Expr.Var "prelude" `Expr.Field` "anyVersion"
+
+                Cabal.IntersectVersionRanges ( Cabal.LaterVersion ( Cabal.versionNumbers -> [ 1 ] ) ) ( Cabal.EarlierVersion ( Cabal.versionNumbers -> [ 1 ] ) ) ->
+                  Expr.Var "prelude" `Expr.Field` "noVersion"
+
+                Cabal.ThisVersion v ->
+                  Expr.App
+                    ( Expr.Var "prelude" `Expr.Field` "thisVersion" )
+                    ( Dhall.embed versionToDhall v )
+
+                Cabal.UnionVersionRanges ( Cabal.EarlierVersion v ) ( Cabal.LaterVersion v' ) | v == v' ->
+                  Expr.App
+                    ( Expr.Var "prelude" `Expr.Field` "notThisVersion" )
+                    ( Dhall.embed versionToDhall v )
+
+                Cabal.LaterVersion v ->
+                  Expr.App
+                    ( Expr.Var "prelude" `Expr.Field` "laterVersion" )
+                    ( Dhall.embed versionToDhall v )
+
+                Cabal.UnionVersionRanges ( Cabal.ThisVersion v ) ( Cabal.LaterVersion v' ) | v == v' ->
+                  Expr.App
+                    ( Expr.Var "prelude" `Expr.Field` "orLaterVersion" )
+                    ( Dhall.embed versionToDhall v )
+
+                Cabal.EarlierVersion v ->
+                  Expr.App
+                    ( Expr.Var "prelude" `Expr.Field` "earlierVersion" )
+                    ( Dhall.embed versionToDhall v )
+
+                Cabal.UnionVersionRanges ( Cabal.ThisVersion v ) ( Cabal.EarlierVersion v' ) | v == v' ->
+                  Expr.App
+                    ( Expr.Var "prelude" `Expr.Field` "orEarlierVersion" )
+                    ( Dhall.embed versionToDhall v )
+
+                Cabal.UnionVersionRanges a b ->
+                  Expr.App
+                    ( Expr.App ( Expr.Var "prelude" `Expr.Field` "unionVersionRanges" ) ( go a ) )
+                    ( go b )
+
+                Cabal.IntersectVersionRanges a b ->
+                  Expr.App
+                    ( Expr.App ( Expr.Var "prelude" `Expr.Field` "intersectVersionRanges" ) ( go a ) )
+                    ( go b )
+
+                Cabal.WildcardVersion v ->
+                  Expr.App
+                    ( Expr.Var "prelude" `Expr.Field` "withinVersion" )
+                    ( Dhall.embed versionToDhall v )
+
+                Cabal.MajorBoundVersion v ->
+                  Expr.App
+                    ( Expr.Var "prelude" `Expr.Field` "majorBoundVersion" )
+                    ( Dhall.embed versionToDhall v )
+
+                Cabal.VersionRangeParens vr ->
+                  go vr
+
+          in
+          go ( Cabal.fromVersionIntervals ( Cabal.toVersionIntervals versionRange0 ) )
+    , Dhall.declared =
+        Expr.Var "types" `Expr.Field` "VersionRange"
+    }
+
+
+sourceRepo :: Dhall.InputType Cabal.SourceRepo
+sourceRepo =
+  runRecordInputType
+    ( mconcat
+        [ recordField "kind" ( contramap Cabal.repoKind repoKind )
+        , recordField "type" ( contramap Cabal.repoType ( maybeToDhall repoType ) )
+        , recordField "location" ( contramap Cabal.repoLocation ( maybeToDhall stringToDhall ) )
+        , recordField "module" ( contramap Cabal.repoModule ( maybeToDhall stringToDhall ) )
+        , recordField "branch" ( contramap Cabal.repoBranch ( maybeToDhall stringToDhall ) )
+        , recordField "tag" ( contramap Cabal.repoTag ( maybeToDhall stringToDhall ) )
+        , recordField "subdir" ( contramap Cabal.repoSubdir ( maybeToDhall stringToDhall ) )
+        ]
+    )
+
+
+repoKind :: Dhall.InputType Cabal.RepoKind
+repoKind =
+  ( runUnion
+      ( mconcat
+          [ unionAlt "RepoThis" ( \x -> case x of Cabal.RepoThis -> Just () ; _ -> Nothing) Dhall.inject
+          , unionAlt "RepoKindUnknown" ( \x -> case x of Cabal.RepoKindUnknown str -> Just  str ; _ -> Nothing) ( runRecordInputType ( recordField "_1" stringToDhall ) )
+          , unionAlt "RepoHead" ( \x -> case x of Cabal.RepoHead -> Just () ; _ -> Nothing) Dhall.inject
+          ]
+      )
+  )
+    { Dhall.declared =
+         Expr.Var "types" `Expr.Field` "RepoKind"
+    }
+
+
+repoType :: Dhall.InputType Cabal.RepoType
+repoType =
+  ( runUnion
+      ( mconcat
+          [ unionAlt "Darcs" ( \x -> case x of Cabal.Darcs -> Just () ; _ -> Nothing ) Dhall.inject
+          , unionAlt "Git" ( \x -> case x of Cabal.Git -> Just () ; _ -> Nothing ) Dhall.inject
+          , unionAlt "SVN" ( \x -> case x of Cabal.SVN -> Just () ; _ -> Nothing ) Dhall.inject
+          , unionAlt "CVS" ( \x -> case x of Cabal.CVS -> Just () ; _ -> Nothing ) Dhall.inject
+          , unionAlt "Mercurial" ( \x -> case x of Cabal.Mercurial -> Just () ; _ -> Nothing ) Dhall.inject
+          , unionAlt "GnuArch" ( \x -> case x of Cabal.GnuArch -> Just () ; _ -> Nothing ) Dhall.inject
+          , unionAlt "Monotone" ( \x -> case x of Cabal.Monotone -> Just () ; _ -> Nothing ) Dhall.inject
+          , unionAlt "OtherRepoType" ( \x -> case x of Cabal.OtherRepoType s -> Just s ; _ -> Nothing ) ( runRecordInputType ( recordField "_1" stringToDhall ) )
+          , unionAlt "Bazaar" ( \x -> case x of Cabal.Bazaar -> Just () ; _ -> Nothing ) Dhall.inject
+          ]
+      )
+  )
+    { Dhall.declared =
+        Expr.Var "types" `Expr.Field` "RepoType"
+    }
+
+
+specVersion :: Dhall.InputType ( Either Cabal.Version Cabal.VersionRange )
+specVersion =
+  Dhall.InputType
+    { Dhall.embed = either ( Dhall.embed versionToDhall ) ( error "Only exact cabal-versions are supported" )
+    , Dhall.declared = Dhall.declared versionToDhall
+    }
+
+
+buildType :: Dhall.InputType Cabal.BuildType
+buildType =
+  Dhall.InputType
+    { Dhall.embed = \case
+        Cabal.Simple ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "BuildTypes" `Expr.Field` "Simple" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.Configure ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "BuildTypes" `Expr.Field` "Configure" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.Custom ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "BuildTypes" `Expr.Field` "Custom" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.Make ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "BuildTypes" `Expr.Field` "Make" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.UnknownBuildType s ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "BuildTypes" `Expr.Field` "UnknownBuildType" )
+            ( Expr.RecordLit ( Map.singleton "_1" ( Dhall.embed Dhall.inject s ) ) )
+
+    , Dhall.declared =
+        Expr.Var "types" `Expr.Field` "BuildType"
+    }
+
+
+setupBuildInfo :: Dhall.InputType Cabal.SetupBuildInfo
+setupBuildInfo =
+  ( runRecordInputType
+      ( mconcat
+          [ recordField "setup-depends" ( contramap Cabal.setupDepends ( listOf dependency ) )
+          ]
+      )
+  )
+    { Dhall.declared =
+        Expr.Var "types" `Expr.Field` "CustomSetup"
+    }
+
+
+dependency :: Dhall.InputType Cabal.Dependency
+dependency =
+  runRecordInputType
+    ( mconcat
+        [ recordField "package" ( contramap ( \( Cabal.Dependency p _ ) -> p ) packageNameToDhall )
+        , recordField "bounds" ( contramap ( \( Cabal.Dependency _ a ) -> a ) versionRange )
+        ]
+    )
+
+
+flag :: Dhall.InputType Cabal.Flag
+flag =
+  runRecordInputType
+    ( mconcat
+        [ recordField "name" ( contramap Cabal.flagName flagName )
+        , recordField "default" ( contramap Cabal.flagDefault Dhall.inject )
+        , recordField "description" ( contramap Cabal.flagDescription stringToDhall )
+        , recordField "manual" ( contramap Cabal.flagManual Dhall.inject )
+        ]
+    )
+
+
+flagName :: Dhall.InputType Cabal.FlagName
+flagName =
+  contramap Cabal.unFlagName stringToDhall
+
+
+library :: Dhall.InputType Cabal.Library
+library =
+  ( runRecordInputType
+      ( mconcat
+          [ contramap Cabal.libBuildInfo buildInfoRecord
+          , recordField
+              "exposed-modules"
+              ( contramap Cabal.exposedModules ( listOf moduleName ) )
+          , recordField
+              "reexported-modules"
+              ( contramap Cabal.reexportedModules ( listOf moduleReexport ) )
+          , recordField
+              "signatures"
+              ( contramap Cabal.signatures ( listOf moduleName ) )
+          ]
+      )
+  )
+    { Dhall.declared =
+        Expr.Var "types" `Expr.Field` "Library"
+    }
+
+
+data CondIfTree v a
+  = Val a
+  | If v ( CondIfTree v a ) ( CondIfTree v a )
+  deriving (Eq, Show)
+
+
+unifyCondTree
+  :: ( Monoid a, Monoid x )
+  => Cabal.CondTree v x a
+  -> CondIfTree ( Cabal.Condition v ) a
+unifyCondTree =
+  let
+    go acc condTree =
+      case Cabal.condTreeComponents condTree of
+        [] ->
+          Val ( acc <> Cabal.condTreeData condTree )
+
+        [c] ->
+          If
+            ( Cabal.condBranchCondition c )
+            ( go
+                ( acc <> Cabal.condTreeData condTree )
+                ( Cabal.condBranchIfTrue c )
+            )
+            ( go
+                ( acc <> Cabal.condTreeData condTree )
+                ( case Cabal.condBranchIfFalse c of
+                    Nothing ->
+                      Cabal.CondNode mempty mempty mempty
+
+                    Just c ->
+                      c
+                )
+            )
+
+        (c:cs) ->
+          go acc ( condTree { Cabal.condTreeComponents = pushDownBranch c <$> cs } )
+
+    pushDownBranch a b =
+      b
+        { Cabal.condBranchIfTrue =
+            pushDownTree a ( Cabal.condBranchIfTrue b )
+        , Cabal.condBranchIfFalse =
+            case Cabal.condBranchIfFalse b of
+              Nothing ->
+                Just ( Cabal.CondNode mempty mempty [a] )
+
+              Just tree ->
+                Just ( pushDownTree a tree )
+        }
+
+    pushDownTree a b =
+      b { Cabal.condTreeComponents = a : Cabal.condTreeComponents b }
+
+  in
+  go mempty
+
+
+condTree
+  :: ( Monoid a, Monoid x )
+  => Dhall.InputType a
+  -> Dhall.InputType ( Cabal.CondTree Cabal.ConfVar x a )
+condTree t =
+  let
+    go = \case
+      Val a ->
+        Dhall.embed t a
+
+      If cond a b ->
+        Expr.BoolIf
+          ( Dhall.embed condBranchCondition cond )
+          ( go a )
+          ( go b )
+
+    configRecord =
+      Expr.Var "types" `Expr.Field` "ConfigOptions"
+
+  in
+  Dhall.InputType
+    { Dhall.embed =
+        Expr.Lam "config" configRecord
+          . go
+          . unifyCondTree
+    , Dhall.declared =
+        Expr.Pi "_" configRecord ( Dhall.declared t )
+    }
+
+
+moduleName :: Dhall.InputType Cabal.ModuleName
+moduleName =
+  contramap ( show . Cabal.disp ) stringToDhall
+
+
+condBranchCondition :: Dhall.InputType (Cabal.Condition Cabal.ConfVar)
+condBranchCondition =
+  Dhall.InputType
+    { Dhall.declared = Expr.Bool
+    , Dhall.embed =
+        \a ->
+          case a of
+            Cabal.Var ( Cabal.OS os0 ) ->
+              Expr.App ( Expr.Field ( Expr.Var "config" ) "os" ) ( Dhall.embed os os0 )
+
+            Cabal.Var ( Cabal.Arch arch0 ) ->
+              Expr.App ( Expr.Field ( Expr.Var "config" ) "arch" ) ( Dhall.embed arch arch0 )
+
+            Cabal.Var ( Cabal.Flag flagName0 ) ->
+              Expr.App ( Expr.Field ( Expr.Var "config" ) "flag" ) ( Dhall.embed flagName flagName0 )
+
+            Cabal.Var ( Cabal.Impl c v ) ->
+              Expr.App ( Expr.App ( Expr.Field ( Expr.Var "config" ) "impl" ) ( Dhall.embed compilerFlavor c ) ) ( Dhall.embed versionRange v )
+
+            Cabal.Lit b ->
+              Expr.BoolLit b
+
+            Cabal.CNot c ->
+              Expr.BoolEQ ( Expr.BoolLit False ) ( Dhall.embed condBranchCondition c )
+
+            Cabal.CAnd a b ->
+              Expr.BoolAnd ( Dhall.embed condBranchCondition a ) ( Dhall.embed condBranchCondition b )
+
+            Cabal.COr a b ->
+              Expr.BoolOr ( Dhall.embed condBranchCondition a ) ( Dhall.embed condBranchCondition b )
+    }
+
+
+os :: Dhall.InputType Cabal.OS
+os =
+  Dhall.InputType
+    { Dhall.embed = \case
+        Cabal.Linux ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "Linux" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.Windows ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "Windows" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.OSX ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "OSX" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.FreeBSD ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "FreeBSD" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.OpenBSD ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "OpenBSD" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.NetBSD ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "NetBSD" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.DragonFly ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "DragonFly" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.Solaris ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "Solaris" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.AIX ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "AIX" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.HPUX ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "HPUX" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.IRIX ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "IRIX" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.HaLVM ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "HaLVM" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.Hurd ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "Hurd" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.IOS ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "IOS" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.Android ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "Android" )
+            ( Expr.RecordLit mempty )
+
+        Cabal.Ghcjs ->
+          Expr.App
+            ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OSs" `Expr.Field` "Ghcjs" )
+            ( Expr.RecordLit mempty )
+
+    , Dhall.declared =
+        Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "OS"
+    }
+
+
+arch :: Dhall.InputType Cabal.Arch
+arch =
+  runUnion
+    ( mconcat
+        [ unionAlt "I386" ( \x -> case x of Cabal.I386 -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "X86_64" ( \x -> case x of Cabal.X86_64 -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "PPC" ( \x -> case x of Cabal.PPC -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "PPC64" ( \x -> case x of Cabal.PPC64 -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "Sparc" ( \x -> case x of Cabal.Sparc -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "Arm" ( \x -> case x of Cabal.Arm -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "Mips" ( \x -> case x of Cabal.Mips -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "SH" ( \x -> case x of Cabal.SH -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "IA64" ( \x -> case x of Cabal.IA64 -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "S390" ( \x -> case x of Cabal.S390 -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "Alpha" ( \x -> case x of Cabal.Alpha -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "Hppa" ( \x -> case x of Cabal.Hppa -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "Rs6000" ( \x -> case x of Cabal.Rs6000 -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "M68k" ( \x -> case x of Cabal.M68k -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "Vax" ( \x -> case x of Cabal.Vax -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "JavaScript" ( \x -> case x of Cabal.JavaScript -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "OtherArch" ( \x -> case x of Cabal.OtherArch s -> Just s ; _ -> Nothing ) ( runRecordInputType ( recordField "_1" stringToDhall ) )
+        ]
+    )
+
+
+buildInfoRecord :: RecordInputType Cabal.BuildInfo
+buildInfoRecord =
+  mconcat
+    [ recordField "buildable" ( contramap Cabal.buildable Dhall.inject )
+    , recordField "build-tools" ( contramap Cabal.buildTools ( listOf legacyExeDependency ) )
+    , recordField "build-tool-depends" ( contramap Cabal.buildToolDepends ( listOf exeDependency ) )
+    , recordField "cpp-options" ( contramap Cabal.cppOptions ( listOf stringToDhall ) )
+    , recordField "cc-options" ( contramap Cabal.ccOptions ( listOf stringToDhall ) )
+    , recordField "ld-options" ( contramap Cabal.ldOptions ( listOf stringToDhall ) )
+    , recordField "pkgconfig-depends" ( contramap Cabal.pkgconfigDepends ( listOf pkgconfigDependency ) )
+    , recordField "frameworks" ( contramap Cabal.frameworks ( listOf stringToDhall ) )
+    , recordField "extra-framework-dirs" ( contramap Cabal.extraFrameworkDirs ( listOf stringToDhall ) )
+    , recordField "c-sources" ( contramap Cabal.cSources ( listOf stringToDhall ) )
+    , recordField "js-sources" ( contramap Cabal.jsSources ( listOf stringToDhall ) )
+    , recordField "hs-source-dirs" ( contramap Cabal.hsSourceDirs ( listOf stringToDhall ) )
+    , recordField "other-modules" ( contramap Cabal.otherModules ( listOf moduleName ) )
+    , recordField "autogen-modules" ( contramap Cabal.autogenModules ( listOf moduleName ) )
+    , recordField "default-language" ( contramap Cabal.defaultLanguage ( maybeToDhall language ) )
+    , recordField "other-languages" ( contramap Cabal.otherLanguages ( listOf language ) )
+    , recordField "default-extensions" ( Cabal.defaultExtensions >$< listOf extension )
+    , recordField "other-extensions" ( Cabal.otherExtensions >$< listOf extension )
+    , recordField "extra-libraries" ( Cabal.extraLibs >$< listOf stringToDhall )
+    , recordField "extra-ghci-libraries" ( Cabal.extraGHCiLibs >$< listOf stringToDhall )
+    , recordField "extra-lib-dirs" ( Cabal.extraLibDirs >$< listOf stringToDhall )
+    , recordField "include-dirs" ( Cabal.includeDirs >$< listOf stringToDhall )
+    , recordField "includes" ( Cabal.includes >$< listOf stringToDhall )
+    , recordField "install-includes" ( Cabal.installIncludes >$< listOf stringToDhall )
+    , recordField "compiler-options" ( Cabal.options >$< compilerOptions )
+    , recordField "profiling-options" ( Cabal.profOptions >$< compilerOptions )
+    , recordField "shared-options" ( Cabal.sharedOptions >$< compilerOptions )
+    , recordField "build-depends" ( Cabal.targetBuildDepends >$< listOf dependency )
+    , recordField "mixins" ( Cabal.mixins >$< listOf mixin )
+    ]
+
+
+moduleReexport :: Dhall.InputType Cabal.ModuleReexport
+moduleReexport =
+  runRecordInputType
+    ( mconcat
+        [ recordField "original"
+             ( ( \a -> ( Cabal.moduleReexportOriginalPackage a, Cabal.moduleReexportOriginalName a ) ) >$<
+                runRecordInputType
+                 ( mconcat
+                     [ recordField "package" ( fst >$< maybeToDhall packageNameToDhall )
+                     , recordField "name" ( snd >$< moduleName )
+                     ]
+                 )
+             )
+        , recordField "name" ( Cabal.moduleReexportName >$< moduleName )
+        ]
+    )
+
+
+legacyExeDependency :: Dhall.InputType Cabal.LegacyExeDependency
+legacyExeDependency =
+  runRecordInputType
+    ( mconcat
+        [ recordField "exe" ( ( \( Cabal.LegacyExeDependency exe _ ) -> exe ) >$< stringToDhall )
+        , recordField "version" ( ( \( Cabal.LegacyExeDependency _ version ) -> version ) >$< versionRange )
+        ]
+    )
+
+exeDependency :: Dhall.InputType Cabal.ExeDependency
+exeDependency =
+  runRecordInputType
+    ( mconcat
+        [ recordField "package" ( ( \( Cabal.ExeDependency packageName _ _ ) -> packageName ) >$< packageNameToDhall )
+        , recordField "component" ( ( \( Cabal.ExeDependency _ component _ ) -> component ) >$< unqualComponentName )
+        , recordField "version" ( ( \( Cabal.ExeDependency _ _ version ) -> version ) >$< versionRange )
+        ]
+    )
+
+
+unqualComponentName :: Dhall.InputType Cabal.UnqualComponentName
+unqualComponentName =
+  show . Cabal.disp >$< stringToDhall
+
+
+pkgconfigDependency :: Dhall.InputType Cabal.PkgconfigDependency
+pkgconfigDependency =
+  runRecordInputType
+    ( mconcat
+        [ recordField "name" ( ( \( Cabal.PkgconfigDependency a _version ) -> a ) >$< pkgconfigName )
+        , recordField "version" ( ( \( Cabal.PkgconfigDependency _name a ) -> a ) >$< versionRange )
+        ]
+    )
+
+
+pkgconfigName :: Dhall.InputType Cabal.PkgconfigName
+pkgconfigName =
+  show . Cabal.disp >$< stringToDhall
+
+
+language :: Dhall.InputType Cabal.Language
+language =
+  ( runUnion
+      ( mconcat
+          [ unionAlt "Haskell2010" ( \x -> case x of Cabal.Haskell2010 -> Just () ; _ -> Nothing ) Dhall.inject
+          , unionAlt "UnknownLanguage" ( \x -> case x of Cabal.UnknownLanguage s -> Just s ; _ -> Nothing ) ( runRecordInputType ( recordField "_1" stringToDhall ) )
+          , unionAlt "Haskell98" ( \x -> case x of Cabal.Haskell98 -> Just () ; _ -> Nothing ) Dhall.inject
+          ]
+      )
+  )
+    { Dhall.declared =
+        Expr.Var "types" `Expr.Field` "Language"
+    }
+
+extension :: Dhall.InputType Cabal.Extension
+extension =
+  Dhall.InputType
+    { Dhall.embed =
+        \a ->
+          case a of
+            Cabal.EnableExtension ext ->
+              extWith True ext
+
+            Cabal.DisableExtension ext ->
+              extWith False ext
+
+            _ ->
+              error "Unknown extension"
+    , Dhall.declared =
+        Expr.Var "types" `Expr.Field` "Extension"
+    }
+
+  where
+
+  extName :: Cabal.KnownExtension -> LazyText.Text
+  extName e =
+    LazyText.pack ( show e )
+
+  extWith trueFalse ext =
+    Expr.App
+      ( Expr.Var "prelude" `Expr.Field` "types" `Expr.Field` "Extensions" `Expr.Field` extName ext )
+      ( Expr.BoolLit trueFalse )
+
+
+compilerOptions :: Dhall.InputType [ ( Cabal.CompilerFlavor, [ String ] ) ]
+compilerOptions =
+  Dhall.InputType
+    { Dhall.embed = \l ->
+        case filter ( not . null . snd ) l of
+          [] ->
+            Expr.Var "prelude" `Expr.Field` "defaults" `Expr.Field` "CompilerOptions"
+
+          xs ->
+            Expr.Prefer
+              ( Expr.Var "prelude" `Expr.Field` "defaults" `Expr.Field` "compiler-options" )
+              ( Expr.RecordLit
+                  ( Map.fromList
+                      ( map
+                          ( \( c, opts ) ->
+                              ( LazyText.pack ( show c ), Dhall.embed Dhall.inject opts )
+                          )
+                          xs
+                      )
+                  )
+              )
+    , Dhall.declared =
+        Expr.Var "types" `Expr.Field` "CompilerOptions"
+    }
+
+  where
+
+    field c =
+      recordField ( LazyText.pack ( show c ) ) ( filtering c )
+
+    filtering c =
+      contramap
+        ( \l -> join [ opts | ( c', opts ) <- l, c == c' ] )
+        ( listOf stringToDhall )
+
+
+mixin :: Dhall.InputType Cabal.Mixin
+mixin =
+  ( runRecordInputType
+      ( mconcat
+          [ recordField "package" ( Cabal.mixinPackageName >$< packageNameToDhall )
+          , recordField "renaming" ( Cabal.mixinIncludeRenaming >$< includeRenaming )
+          ]
+      )
+  )
+    { Dhall.declared =
+        Expr.Var "types" `Expr.Field` "Mixin"
+
+    }
+
+
+includeRenaming :: Dhall.InputType Cabal.IncludeRenaming
+includeRenaming =
+  runRecordInputType
+    ( mconcat
+        [ recordField "provides" ( Cabal.includeProvidesRn >$< moduleRenaming )
+        , recordField "requires" ( Cabal.includeRequiresRn >$< moduleRenaming )
+        ]
+    )
+
+
+moduleRenaming :: Dhall.InputType Cabal.ModuleRenaming
+moduleRenaming =
+  ( \( Cabal.ModuleRenaming a ) -> a ) >$<
+  listOf
+    ( runRecordInputType
+        ( mconcat
+            [ recordField "rename" ( ( \( a, _ ) -> a ) >$< moduleName )
+            , recordField "to" ( ( \( _, a ) -> a ) >$< moduleName )
+            ]
+        )
+    )
+
+
+benchmark :: Dhall.InputType Cabal.Benchmark
+benchmark =
+  (  runRecordInputType
+       ( mconcat
+           [ recordField "main-is" ( ( \( Cabal.BenchmarkExeV10 _ s ) -> s ) . Cabal.benchmarkInterface >$< stringToDhall )
+           , Cabal.benchmarkBuildInfo >$< buildInfoRecord
+           ]
+       )
+  )
+    { Dhall.declared =
+        Expr.Var "types" `Expr.Field` "Benchmark"
+    }
+
+
+testSuite :: Dhall.InputType Cabal.TestSuite
+testSuite =
+  ( runRecordInputType
+      ( mconcat
+          [ recordField "type" ( Cabal.testInterface >$< testSuiteInterface )
+          , Cabal.testBuildInfo >$< buildInfoRecord
+          ]
+      )
+  )
+    { Dhall.declared =
+        Expr.Var "types" `Expr.Field` "TestSuite"
+    }
+
+
+testSuiteInterface :: Dhall.InputType Cabal.TestSuiteInterface
+testSuiteInterface =
+  runUnion
+    ( mconcat
+        [ unionAlt
+            "exitcode-stdio"
+            ( \x ->
+                case x of
+                  Cabal.TestSuiteExeV10 _ main ->
+                    Just main
+
+                  _ ->
+                    Nothing
+            )
+            ( runRecordInputType ( recordField "main-is" stringToDhall ) )
+        , unionAlt
+            "detailed"
+            ( \x ->
+                case x of
+                  Cabal.TestSuiteLibV09 _ m ->
+                    Just m
+
+                  _ ->
+                    Nothing
+            )
+            ( runRecordInputType ( recordField "module" moduleName ) )
+        ]
+    )
+
+
+executable :: Dhall.InputType Cabal.Executable
+executable =
+  ( runRecordInputType
+      ( mconcat
+          [ recordField "main-is" ( Cabal.modulePath >$< stringToDhall )
+          , recordField "scope" ( Cabal.exeScope >$< executableScope )
+          , Cabal.buildInfo >$< buildInfoRecord
+          ]
+      )
+  )
+    { Dhall.declared =
+        Expr.Var "types" `Expr.Field` "Executable"
+    }
+
+
+executableScope :: Dhall.InputType Cabal.ExecutableScope
+executableScope =
+  runUnion
+    ( mconcat
+        [ unionAlt
+            "Public"
+            ( \x ->
+                case x of
+                  Cabal.ExecutablePublic -> Just ()
+                  Cabal.ExecutableScopeUnknown -> Just ()
+                  _ -> Nothing
+            )
+            Dhall.inject
+        , unionAlt "Private" ( \x -> case x of Cabal.ExecutablePrivate -> Just () ; _ -> Nothing ) Dhall.inject
+        ]
+    )
+
+
+foreignLibrary :: Dhall.InputType Cabal.ForeignLib
+foreignLibrary =
+  ( runRecordInputType
+      ( mconcat
+          [ recordField "type" ( Cabal.foreignLibType >$< foreignLibType )
+          , recordField "options" ( Cabal.foreignLibOptions >$< ( listOf foreignLibOption ) )
+          , Cabal.foreignLibBuildInfo >$< buildInfoRecord
+          , recordField "lib-version-info" ( Cabal.foreignLibVersionInfo >$< maybeToDhall versionInfo )
+          , recordField "lib-version-linux" ( Cabal.foreignLibVersionLinux >$< maybeToDhall versionToDhall )
+          , recordField "mod-def-files" ( Cabal.foreignLibModDefFile >$< listOf stringToDhall )
+          ]
+      )
+  )
+    { Dhall.declared =
+        Expr.Var "types" `Expr.Field` "ForeignLibrary"
+    }
+
+
+versionInfo :: Dhall.InputType Cabal.LibVersionInfo
+versionInfo =
+  Cabal.libVersionInfoCRA >$<
+  runRecordInputType
+    ( mconcat
+        [ recordField "current" ( ( \( a, _, _ ) -> fromIntegral a :: Natural ) >$< ( Dhall.inject ) )
+        , recordField "revision" ( ( \( _, a, _ ) -> fromIntegral a :: Natural ) >$< ( Dhall.inject ) )
+        , recordField "age" ( ( \( _, _, a ) -> fromIntegral a :: Natural ) >$< ( Dhall.inject ) )
+        ]
+    )
+
+
+foreignLibOption :: Dhall.InputType Cabal.ForeignLibOption
+foreignLibOption =
+  runUnion
+    ( unionAlt "Standalone" ( \x -> case x of Cabal.ForeignLibStandalone -> Just () ; _ -> Nothing ) Dhall.inject
+    )
+
+
+foreignLibType :: Dhall.InputType Cabal.ForeignLibType
+foreignLibType =
+  runUnion
+    ( mconcat
+        [ unionAlt "Shared" ( \x -> case x of Cabal.ForeignLibNativeShared -> Just () ; _ -> Nothing ) Dhall.inject
+        , unionAlt "Static" ( \x -> case x of Cabal.ForeignLibNativeStatic -> Just () ; _ -> Nothing ) Dhall.inject
+        ]
+    )
diff --git a/dhall-to-cabal.cabal b/dhall-to-cabal.cabal
new file mode 100644
--- /dev/null
+++ b/dhall-to-cabal.cabal
@@ -0,0 +1,155 @@
+name: dhall-to-cabal
+version: 1.0.0
+cabal-version: 2.0
+build-type: Simple
+license: MIT
+license-file: LICENSE
+maintainer: ollie@ocharles.org.uk
+homepage: https://github.com/ocharles/dhall-to-cabal
+bug-reports: https://github.com/ocharles/dhall-to-cabal/issues
+synopsis: Compile Dhall expressions to Cabal files
+description:
+    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).
+    .
+category: Distribution
+extra-source-files:
+    Changelog.md
+    dhall/defaults/BuildInfo.dhall
+    dhall/defaults/Library.dhall
+    dhall/defaults/CompilerOptions.dhall
+    dhall/defaults/SourceRepo.dhall
+    dhall/defaults/TestSuite.dhall
+    dhall/defaults/Executable.dhall
+    dhall/defaults/Package.dhall
+    dhall/defaults/Benchmark.dhall
+    dhall/unconditional.dhall
+    dhall/GitHub-project.dhall
+    dhall/prelude.dhall
+    dhall/types/VersionRange.dhall
+    dhall/types/OS.dhall
+    dhall/types/Guarded.dhall
+    dhall/types/License.dhall
+    dhall/types/Library.dhall
+    dhall/types/Version.dhall
+    dhall/types/Language.dhall
+    dhall/types/Extension.dhall
+    dhall/types/CompilerOptions.dhall
+    dhall/types/SourceRepo.dhall
+    dhall/types/TestSuite.dhall
+    dhall/types/Executable.dhall
+    dhall/types/Dependency.dhall
+    dhall/types/Mixin.dhall
+    dhall/types/Compiler.dhall
+    dhall/types/Config.dhall
+    dhall/types/Package.dhall
+    dhall/types/builtin.dhall
+    dhall/types/BuildType.dhall
+    dhall/types/RepoKind.dhall
+    dhall/types/Version/v.dhall
+    dhall/types/Arch.dhall
+    dhall/types/Scope.dhall
+    dhall/types/CustomSetup.dhall
+    dhall/types/Benchmark.dhall
+    dhall/types/Flag.dhall
+    dhall/types/ForeignLibrary.dhall
+    dhall/types/ModuleRenaming.dhall
+    dhall/types/RepoType.dhall
+    dhall/types/TestType.dhall
+    dhall/types/VersionRange/IntersectVersionRanges.dhall
+    dhall/types/VersionRange/WithinVersion.dhall
+    dhall/types/VersionRange/InvertVersionRange.dhall
+    dhall/types/VersionRange/EarlierVersion.dhall
+    dhall/types/VersionRange/DifferenceVersionRanges.dhall
+    dhall/types/VersionRange/ThisVersion.dhall
+    dhall/types/VersionRange/OrLaterVersion.dhall
+    dhall/types/VersionRange/OrEarlierVersion.dhall
+    dhall/types/VersionRange/AnyVersion.dhall
+    dhall/types/VersionRange/NotThisVersion.dhall
+    dhall/types/VersionRange/LaterVersion.dhall
+    dhall/types/VersionRange/NoVersion.dhall
+    dhall/types/VersionRange/MajorBoundVersion.dhall
+    dhall/types/VersionRange/UnionVersionRanges.dhall
+    dhall/types/SetupBuildInfo.dhall
+
+source-repository head
+    type: git
+    location: https://github.com/ocharles/dhall-to-cabal
+
+library
+    exposed-modules:
+        DhallToCabal
+    build-depends:
+        Cabal ^>=2.0,
+        base ^>=4.10,
+        bytestring ^>=0.10,
+        containers ^>=0.5,
+        dhall ^>=1.12.0,
+        formatting ^>=6.3.1,
+        hashable ^>=1.2.6.1,
+        insert-ordered-containers ^>=0.2.1.0,
+        text ^>=1.2,
+        transformers ^>=0.5.2,
+        trifecta ^>=1.7,
+        vector ^>=0.12
+    default-language: Haskell2010
+    other-extensions: ApplicativeDo GADTs GeneralizedNewtypeDeriving
+                      LambdaCase OverloadedStrings RecordWildCards TypeApplications
+    hs-source-dirs: lib
+    other-modules:
+        DhallToCabal.ConfigTree
+        DhallToCabal.Diff
+        Dhall.Extra
+    ghc-options: -Wall -fno-warn-name-shadowing
+
+executable  dhall-to-cabal
+    main-is: Main.hs
+    scope: public
+    build-depends:
+        Cabal ^>=2.0,
+        base ^>=4.10,
+        dhall ^>=1.12.0,
+        dhall-to-cabal -any,
+        optparse-applicative ^>=0.13.2 || ^>=0.14,
+        prettyprinter ^>=1.2.0.1,
+        text ^>=1.2
+    default-language: Haskell2010
+    other-extensions: NamedFieldPuns
+    hs-source-dirs: exe
+
+executable  cabal-to-dhall
+    main-is: Main.hs
+    scope: public
+    build-depends:
+        Cabal ^>=2.0,
+        base ^>=4.10,
+        contravariant ^>=1.4,
+        dhall ^>=1.12.0,
+        hashable ^>=1.2.6.1,
+        dhall-to-cabal -any,
+        insert-ordered-containers ^>=0.2.1.0,
+        optparse-applicative ^>=0.13.2 || ^>=0.14,
+        prettyprinter ^>=1.2.0.1,
+        text ^>=1.2
+    default-language: Haskell2010
+    other-extensions: NamedFieldPuns
+    hs-source-dirs: cabal-to-dhall
+
+test-suite  golden-tests
+    type: exitcode-stdio-1.0
+    main-is: GoldenTests.hs
+    build-depends:
+        base ^>=4.10,
+        Cabal ^>=2.0,
+        Diff ^>=0.3.4,
+        bytestring ^>=0.10,
+        dhall-to-cabal -any,
+        filepath ^>=1.4,
+        tasty ^>=0.11,
+        tasty-golden ^>=2.3,
+        text ^>=1.2
+    default-language: Haskell2010
+    hs-source-dirs: golden-tests
+
diff --git a/dhall/GitHub-project.dhall b/dhall/GitHub-project.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/GitHub-project.dhall
@@ -0,0 +1,26 @@
+    let GitHubProject : Type = { owner : Text, repo : Text }
+
+in  let gitHubProject =
+            λ(github : GitHubProject)
+          →     let gitHubRoot =
+                      "https://github.com/${github.owner}/${github.repo}"
+            
+            in    ./defaults/Package.dhall 
+                ⫽ { name =
+                      github.repo
+                  , bug-reports =
+                      "${gitHubRoot}/issues"
+                  , homepage =
+                      gitHubRoot
+                  , source-repos =
+                      [   ./defaults/SourceRepo.dhall 
+                        ⫽ { location =
+                              [ gitHubRoot ] : Optional Text
+                          , type =
+                              [ (constructors ./types/RepoType.dhall ).Git {=}
+                              ] : Optional ./types/RepoType.dhall 
+                          }
+                      ]
+                  }
+
+in  gitHubProject
diff --git a/dhall/defaults/Benchmark.dhall b/dhall/defaults/Benchmark.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/defaults/Benchmark.dhall
@@ -0,0 +1,1 @@
+./BuildInfo.dhall 
diff --git a/dhall/defaults/BuildInfo.dhall b/dhall/defaults/BuildInfo.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/defaults/BuildInfo.dhall
@@ -0,0 +1,66 @@
+{ autogen-modules =
+    [] : List Text
+, build-depends =
+    [] : List ../types/Dependency.dhall 
+, build-tool-depends =
+    [] : List
+         { component :
+             Text
+         , package :
+             Text
+         , version :
+             ../types/VersionRange.dhall 
+         }
+, build-tools =
+    [] : List { exe : Text, version : ../types/VersionRange.dhall  }
+, buildable =
+    True
+, c-sources =
+    [] : List Text
+, cc-options =
+    [] : List Text
+, compiler-options =
+    ./CompilerOptions.dhall 
+, cpp-options =
+    [] : List Text
+, default-extensions =
+    [] : List ../types/Extension.dhall 
+, default-language =
+    [] : Optional ../types/Language.dhall 
+, extra-framework-dirs =
+    [] : List Text
+, extra-ghci-libraries =
+    [] : List Text
+, extra-lib-dirs =
+    [] : List Text
+, extra-libraries =
+    [] : List Text
+, frameworks =
+    [] : List Text
+, hs-source-dirs =
+    [] : List Text
+, includes =
+    [] : List Text
+, include-dirs =
+    [] : List Text
+, install-includes =
+    [] : List Text
+, js-sources =
+    [] : List Text
+, ld-options =
+    [] : List Text
+, other-extensions =
+    [] : List ../types/Extension.dhall 
+, other-languages =
+    [] : List ../types/Language.dhall 
+, other-modules =
+    [] : List Text
+, pkgconfig-depends =
+    [] : List { name : Text, version : ../types/VersionRange.dhall  }
+, profiling-options =
+    ./CompilerOptions.dhall 
+, shared-options =
+    ./CompilerOptions.dhall 
+, mixins =
+    [] : List ../types/Mixin.dhall 
+}
diff --git a/dhall/defaults/CompilerOptions.dhall b/dhall/defaults/CompilerOptions.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/defaults/CompilerOptions.dhall
@@ -0,0 +1,21 @@
+{ GHC =
+    [] : List Text
+, GHCJS =
+    [] : List Text
+, HBC =
+    [] : List Text
+, Helium =
+    [] : List Text
+, Hugs =
+    [] : List Text
+, JHC =
+    [] : List Text
+, LHC =
+    [] : List Text
+, NHC =
+    [] : List Text
+, UHC =
+    [] : List Text
+, YHC =
+    [] : List Text
+}
diff --git a/dhall/defaults/Executable.dhall b/dhall/defaults/Executable.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/defaults/Executable.dhall
@@ -0,0 +1,2 @@
+  ./BuildInfo.dhall 
+⫽ { main-is = "", scope = (constructors ../types/Scope.dhall ).Public {=} }
diff --git a/dhall/defaults/Library.dhall b/dhall/defaults/Library.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/defaults/Library.dhall
@@ -0,0 +1,11 @@
+  ./BuildInfo.dhall 
+⫽ { exposed-modules =
+      [] : List Text
+  , other-modules =
+      [] : List Text
+  , reexported-modules =
+      [] : List
+           { name : Text, original : { name : Text, package : Optional Text } }
+  , signatures =
+      [] : List Text
+  }
diff --git a/dhall/defaults/Package.dhall b/dhall/defaults/Package.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/defaults/Package.dhall
@@ -0,0 +1,94 @@
+{ author =
+    ""
+, flags =
+    [] : List ../types/Flag.dhall 
+, benchmarks =
+    [] : List
+         { benchmark :
+             ../types/Guarded.dhall  ../types/Benchmark.dhall 
+         , name :
+             Text
+         }
+, bug-reports =
+    ""
+, build-type =
+    [ (constructors ../types/BuildType.dhall ).Simple {=}
+    ] : Optional ../types/BuildType.dhall 
+, cabal-version =
+    ../types/Version/v.dhall  "2.0"
+, category =
+    ""
+, copyright =
+    ""
+, data-dir =
+    ""
+, data-files =
+    [] : List Text
+, description =
+    ""
+, executables =
+    [] : List
+         { executable :
+             ../types/Guarded.dhall  ../types/Executable.dhall 
+         , name :
+             Text
+         }
+, extra-doc-files =
+    [] : List Text
+, extra-source-files =
+    [] : List Text
+, extra-tmp-files =
+    [] : List Text
+, foreign-libraries =
+    [] : List
+         { foreign-lib :
+             ../types/Guarded.dhall  ../types/ForeignLibrary.dhall 
+         , name :
+             Text
+         }
+, homepage =
+    ""
+, library =
+    [] : Optional (../types/Guarded.dhall  ../types/Library.dhall )
+, license =
+    (constructors ../types/License.dhall ).Unspecified {=}
+, license-files =
+    [] : List Text
+, maintainer =
+    ""
+, name =
+    ""
+, package-url =
+    ""
+, source-repos =
+    [] : List ../types/SourceRepo.dhall 
+, stability =
+    ""
+, sub-libraries =
+    [] : List
+         { library :
+             ../types/Guarded.dhall  ../types/Library.dhall 
+         , name :
+             Text
+         }
+, synopsis =
+    ""
+, test-suites =
+    [] : List
+         { name :
+             Text
+         , test-suite :
+             ../types/Guarded.dhall  ../types/TestSuite.dhall 
+         }
+, tested-with =
+    [] : List
+         { compiler :
+             ../types/Compiler.dhall 
+         , version :
+             ../types/VersionRange.dhall 
+         }
+, x-fields =
+    [] : List { _1 : Text, _2 : Text }
+, custom-setup =
+    [] : Optional ../types/SetupBuildInfo.dhall 
+}
diff --git a/dhall/defaults/SourceRepo.dhall b/dhall/defaults/SourceRepo.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/defaults/SourceRepo.dhall
@@ -0,0 +1,15 @@
+{ type =
+    [] : Optional ../types/RepoType.dhall 
+, location =
+    [] : Optional Text
+, module =
+    [] : Optional Text
+, branch =
+    [] : Optional Text
+, tag =
+    [] : Optional Text
+, subdir =
+    [] : Optional Text
+, kind =
+    (constructors ../types/RepoKind.dhall ).RepoHead {=}
+}
diff --git a/dhall/defaults/TestSuite.dhall b/dhall/defaults/TestSuite.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/defaults/TestSuite.dhall
@@ -0,0 +1,1 @@
+./BuildInfo.dhall 
diff --git a/dhall/prelude.dhall b/dhall/prelude.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/prelude.dhall
@@ -0,0 +1,114 @@
+{ types =
+    { BuildTypes =
+        constructors ./types/BuildType.dhall 
+    , OSs =
+        constructors ./types/OS.dhall 
+    , Compilers =
+        constructors ./types/Compiler.dhall 
+    , Extensions =
+        constructors ./types/Extension.dhall 
+    , Languages =
+        constructors ./types/Language.dhall 
+    , Licenses =
+        constructors ./types/License.dhall 
+    , TestTypes =
+        constructors ./types/TestType.dhall 
+    }
+, defaults =
+    { CompilerOptions =
+        ./defaults/CompilerOptions.dhall 
+    , Library =
+        ./defaults/Library.dhall 
+    , Benchmark =
+        ./defaults/Benchmark.dhall 
+    , Executable =
+        ./defaults/Executable.dhall 
+    , Package =
+        ./defaults/Package.dhall 
+    , SourceRepo =
+        ./defaults/SourceRepo.dhall 
+    , TestSuite =
+        ./defaults/TestSuite.dhall 
+    }
+, anyVersion =
+    ./types/VersionRange/AnyVersion.dhall 
+, earlierVersion =
+    ./types/VersionRange/EarlierVersion.dhall 
+, orEarlierVersion =
+    ./types/VersionRange/OrEarlierVersion.dhall 
+, intersectVersionRanges =
+    ./types/VersionRange/IntersectVersionRanges.dhall 
+, unionVersionRanges =
+    ./types/VersionRange/UnionVersionRanges.dhall 
+, majorBoundVersion =
+    ./types/VersionRange/MajorBoundVersion.dhall 
+, orLaterVersion =
+    ./types/VersionRange/OrLaterVersion.dhall 
+, laterVersion =
+    ./types/VersionRange/LaterVersion.dhall 
+, thisVersion =
+    ./types/VersionRange/ThisVersion.dhall 
+, notThisVersion =
+    ./types/VersionRange/NotThisVersion.dhall 
+, withinVersion =
+    ./types/VersionRange/WithinVersion.dhall 
+, v =
+    ./types/Version/v.dhall 
+, noVersion =
+    ./types/VersionRange/NoVersion.dhall 
+, utils =
+    { majorVersions =
+            let majorVersions
+                :   Text
+                  → List ./types/Version.dhall 
+                  → { package : Text, bounds : ./types/VersionRange.dhall  }
+                =   λ ( package
+                      : Text
+                      )
+                  → λ(versions : List ./types/Version.dhall )
+                  → { package =
+                        package
+                    , bounds =
+                        Optional/fold
+                        ./types/VersionRange.dhall 
+                        ( List/fold
+                          ./types/Version.dhall 
+                          versions
+                          (Optional ./types/VersionRange.dhall )
+                          (   λ ( v
+                                : ./types/Version.dhall 
+                                )
+                            → λ(r : Optional ./types/VersionRange.dhall )
+                            → Optional/fold
+                              ./types/VersionRange.dhall 
+                              r
+                              (Optional ./types/VersionRange.dhall )
+                              (   λ ( r
+                                    : ./types/VersionRange.dhall 
+                                    )
+                                → [ ./types/VersionRange/UnionVersionRanges.dhall 
+                                    ( ./types/VersionRange/MajorBoundVersion.dhall 
+                                      v
+                                    )
+                                    r
+                                  ] : Optional ./types/VersionRange.dhall 
+                              )
+                              ( [ ./types/VersionRange/MajorBoundVersion.dhall 
+                                  v
+                                ] : Optional ./types/VersionRange.dhall 
+                              )
+                          )
+                          ([] : Optional ./types/VersionRange.dhall )
+                        )
+                        ./types/VersionRange.dhall 
+                        (λ(a : ./types/VersionRange.dhall ) → a)
+                        ./types/VersionRange/NoVersion.dhall 
+                    }
+        
+        in  majorVersions
+    , GitHub-project =
+        ./GitHub-project.dhall 
+    }
+, unconditional =
+    ./unconditional.dhall 
+}
diff --git a/dhall/types/Arch.dhall b/dhall/types/Arch.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Arch.dhall
@@ -0,0 +1,35 @@
+< Alpha :
+    {}
+| Arm :
+    {}
+| Hppa :
+    {}
+| I386 :
+    {}
+| IA64 :
+    {}
+| JavaScript :
+    {}
+| M68k :
+    {}
+| Mips :
+    {}
+| OtherArch :
+    { _1 : Text }
+| PPC :
+    {}
+| PPC64 :
+    {}
+| Rs6000 :
+    {}
+| S390 :
+    {}
+| SH :
+    {}
+| Sparc :
+    {}
+| Vax :
+    {}
+| X86_64 :
+    {}
+>
diff --git a/dhall/types/Benchmark.dhall b/dhall/types/Benchmark.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Benchmark.dhall
@@ -0,0 +1,61 @@
+{ autogen-modules :
+    List Text
+, build-depends :
+    List ./Dependency.dhall 
+, build-tool-depends :
+    List { component : Text, package : Text, version : ./VersionRange.dhall  }
+, build-tools :
+    List { exe : Text, version : ./VersionRange.dhall  }
+, buildable :
+    Bool
+, c-sources :
+    List Text
+, cc-options :
+    List Text
+, compiler-options :
+    ./CompilerOptions.dhall 
+, cpp-options :
+    List Text
+, default-extensions :
+    List ./Extension.dhall 
+, default-language :
+    Optional ./Language.dhall 
+, extra-framework-dirs :
+    List Text
+, extra-ghci-libraries :
+    List Text
+, extra-lib-dirs :
+    List Text
+, extra-libraries :
+    List Text
+, frameworks :
+    List Text
+, hs-source-dirs :
+    List Text
+, includes :
+    List Text
+, include-dirs :
+    List Text
+, install-includes :
+    List Text
+, js-sources :
+    List Text
+, ld-options :
+    List Text
+, main-is :
+    Text
+, other-extensions :
+    List ./Extension.dhall 
+, other-languages :
+    List ./Language.dhall 
+, other-modules :
+    List Text
+, pkgconfig-depends :
+    List { name : Text, version : ./VersionRange.dhall  }
+, profiling-options :
+    ./CompilerOptions.dhall 
+, shared-options :
+    ./CompilerOptions.dhall 
+, mixins :
+    List ./Mixin.dhall 
+}
diff --git a/dhall/types/BuildType.dhall b/dhall/types/BuildType.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/BuildType.dhall
@@ -0,0 +1,11 @@
+< Configure :
+    {}
+| Custom :
+    {}
+| Make :
+    {}
+| Simple :
+    {}
+| UnknownBuildType :
+    { _1 : Text }
+>
diff --git a/dhall/types/Compiler.dhall b/dhall/types/Compiler.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Compiler.dhall
@@ -0,0 +1,25 @@
+< GHC :
+    {}
+| GHCJS :
+    {}
+| HBC :
+    {}
+| HaskellSuite :
+    { _1 : Text }
+| Helium :
+    {}
+| Hugs :
+    {}
+| JHC :
+    {}
+| LHC :
+    {}
+| NHC :
+    {}
+| OtherCompiler :
+    { _1 : Text }
+| UHC :
+    {}
+| YHC :
+    {}
+>
diff --git a/dhall/types/CompilerOptions.dhall b/dhall/types/CompilerOptions.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/CompilerOptions.dhall
@@ -0,0 +1,21 @@
+{ GHC :
+    List Text
+, GHCJS :
+    List Text
+, HBC :
+    List Text
+, Helium :
+    List Text
+, Hugs :
+    List Text
+, JHC :
+    List Text
+, LHC :
+    List Text
+, NHC :
+    List Text
+, UHC :
+    List Text
+, YHC :
+    List Text
+}
diff --git a/dhall/types/Config.dhall b/dhall/types/Config.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Config.dhall
@@ -0,0 +1,9 @@
+{ os :
+    ./OS.dhall  → Bool
+, arch :
+    ./Arch.dhall  → Bool
+, impl :
+    ./Compiler.dhall  → ./VersionRange.dhall  → Bool
+, flag :
+    Text → Bool
+}
diff --git a/dhall/types/CustomSetup.dhall b/dhall/types/CustomSetup.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/CustomSetup.dhall
@@ -0,0 +1,1 @@
+{ setup-depends : List ./Dependency.dhall  }
diff --git a/dhall/types/Dependency.dhall b/dhall/types/Dependency.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Dependency.dhall
@@ -0,0 +1,1 @@
+{ bounds : ./VersionRange.dhall , package : Text }
diff --git a/dhall/types/Executable.dhall b/dhall/types/Executable.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Executable.dhall
@@ -0,0 +1,63 @@
+{ autogen-modules :
+    List Text
+, build-depends :
+    List ./Dependency.dhall 
+, build-tool-depends :
+    List { component : Text, package : Text, version : ./VersionRange.dhall  }
+, build-tools :
+    List { exe : Text, version : ./VersionRange.dhall  }
+, buildable :
+    Bool
+, c-sources :
+    List Text
+, cc-options :
+    List Text
+, compiler-options :
+    ./CompilerOptions.dhall 
+, cpp-options :
+    List Text
+, default-extensions :
+    List ./Extension.dhall 
+, default-language :
+    Optional ./Language.dhall 
+, extra-framework-dirs :
+    List Text
+, extra-ghci-libraries :
+    List Text
+, extra-lib-dirs :
+    List Text
+, extra-libraries :
+    List Text
+, frameworks :
+    List Text
+, hs-source-dirs :
+    List Text
+, includes :
+    List Text
+, include-dirs :
+    List Text
+, install-includes :
+    List Text
+, js-sources :
+    List Text
+, ld-options :
+    List Text
+, other-extensions :
+    List ./Extension.dhall 
+, other-languages :
+    List ./Language.dhall 
+, other-modules :
+    List Text
+, pkgconfig-depends :
+    List { name : Text, version : ./VersionRange.dhall  }
+, profiling-options :
+    ./CompilerOptions.dhall 
+, shared-options :
+    ./CompilerOptions.dhall 
+, main-is :
+    Text
+, scope :
+    ./Scope.dhall 
+, mixins :
+    List ./Mixin.dhall 
+}
diff --git a/dhall/types/Extension.dhall b/dhall/types/Extension.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Extension.dhall
@@ -0,0 +1,239 @@
+< AllowAmbiguousTypes :
+    Bool
+| ApplicativeDo :
+    Bool
+| Arrows :
+    Bool
+| AutoDeriveTypeable :
+    Bool
+| BangPatterns :
+    Bool
+| BinaryLiterals :
+    Bool
+| CApiFFI :
+    Bool
+| CPP :
+    Bool
+| ConstrainedClassMethods :
+    Bool
+| ConstraintKinds :
+    Bool
+| DataKinds :
+    Bool
+| DatatypeContexts :
+    Bool
+| DefaultSignatures :
+    Bool
+| DeriveAnyClass :
+    Bool
+| DeriveDataTypeable :
+    Bool
+| DeriveFoldable :
+    Bool
+| DeriveFunctor :
+    Bool
+| DeriveGeneric :
+    Bool
+| DeriveLift :
+    Bool
+| DeriveTraversable :
+    Bool
+| DisambiguateRecordFields :
+    Bool
+| DoAndIfThenElse :
+    Bool
+| DoRec :
+    Bool
+| DuplicateRecordFields :
+    Bool
+| EmptyCase :
+    Bool
+| EmptyDataDecls :
+    Bool
+| ExistentialQuantification :
+    Bool
+| ExplicitForAll :
+    Bool
+| ExplicitNamespaces :
+    Bool
+| ExtendedDefaultRules :
+    Bool
+| ExtensibleRecords :
+    Bool
+| FlexibleContexts :
+    Bool
+| FlexibleInstances :
+    Bool
+| ForeignFunctionInterface :
+    Bool
+| FunctionalDependencies :
+    Bool
+| GADTSyntax :
+    Bool
+| GADTs :
+    Bool
+| GHCForeignImportPrim :
+    Bool
+| GeneralizedNewtypeDeriving :
+    Bool
+| Generics :
+    Bool
+| HereDocuments :
+    Bool
+| ImplicitParams :
+    Bool
+| ImplicitPrelude :
+    Bool
+| ImpredicativeTypes :
+    Bool
+| IncoherentInstances :
+    Bool
+| InstanceSigs :
+    Bool
+| InterruptibleFFI :
+    Bool
+| JavaScriptFFI :
+    Bool
+| KindSignatures :
+    Bool
+| LambdaCase :
+    Bool
+| LiberalTypeSynonyms :
+    Bool
+| MagicHash :
+    Bool
+| MonadComprehensions :
+    Bool
+| MonadFailDesugaring :
+    Bool
+| MonoLocalBinds :
+    Bool
+| MonoPatBinds :
+    Bool
+| MonomorphismRestriction :
+    Bool
+| MultiParamTypeClasses :
+    Bool
+| MultiWayIf :
+    Bool
+| NPlusKPatterns :
+    Bool
+| NamedFieldPuns :
+    Bool
+| NamedWildCards :
+    Bool
+| NegativeLiterals :
+    Bool
+| NewQualifiedOperators :
+    Bool
+| NondecreasingIndentation :
+    Bool
+| NullaryTypeClasses :
+    Bool
+| NumDecimals :
+    Bool
+| OverlappingInstances :
+    Bool
+| OverloadedLabels :
+    Bool
+| OverloadedLists :
+    Bool
+| OverloadedStrings :
+    Bool
+| PackageImports :
+    Bool
+| ParallelArrays :
+    Bool
+| ParallelListComp :
+    Bool
+| PartialTypeSignatures :
+    Bool
+| PatternGuards :
+    Bool
+| PatternSignatures :
+    Bool
+| PatternSynonyms :
+    Bool
+| PolyKinds :
+    Bool
+| PolymorphicComponents :
+    Bool
+| PostfixOperators :
+    Bool
+| QuasiQuotes :
+    Bool
+| Rank2Types :
+    Bool
+| RankNTypes :
+    Bool
+| RebindableSyntax :
+    Bool
+| RecordPuns :
+    Bool
+| RecordWildCards :
+    Bool
+| RecursiveDo :
+    Bool
+| RegularPatterns :
+    Bool
+| RelaxedPolyRec :
+    Bool
+| RestrictedTypeSynonyms :
+    Bool
+| RoleAnnotations :
+    Bool
+| Safe :
+    Bool
+| SafeImports :
+    Bool
+| ScopedTypeVariables :
+    Bool
+| StandaloneDeriving :
+    Bool
+| StaticPointers :
+    Bool
+| Strict :
+    Bool
+| StrictData :
+    Bool
+| TemplateHaskell :
+    Bool
+| TemplateHaskellQuotes :
+    Bool
+| TraditionalRecordSyntax :
+    Bool
+| TransformListComp :
+    Bool
+| Trustworthy :
+    Bool
+| TupleSections :
+    Bool
+| TypeApplications :
+    Bool
+| TypeFamilies :
+    Bool
+| TypeFamilyDependencies :
+    Bool
+| TypeInType :
+    Bool
+| TypeOperators :
+    Bool
+| TypeSynonymInstances :
+    Bool
+| UnboxedTuples :
+    Bool
+| UndecidableInstances :
+    Bool
+| UndecidableSuperClasses :
+    Bool
+| UnicodeSyntax :
+    Bool
+| UnliftedFFITypes :
+    Bool
+| Unsafe :
+    Bool
+| ViewPatterns :
+    Bool
+| XmlSyntax :
+    Bool
+>
diff --git a/dhall/types/Flag.dhall b/dhall/types/Flag.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Flag.dhall
@@ -0,0 +1,1 @@
+{ default : Bool, description : Text, manual : Bool, name : Text }
diff --git a/dhall/types/ForeignLibrary.dhall b/dhall/types/ForeignLibrary.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/ForeignLibrary.dhall
@@ -0,0 +1,69 @@
+{ autogen-modules :
+    List Text
+, build-depends :
+    List ./Dependency.dhall 
+, build-tool-depends :
+    List { component : Text, package : Text, version : ./VersionRange.dhall  }
+, build-tools :
+    List { exe : Text, version : ./VersionRange.dhall  }
+, buildable :
+    Bool
+, c-sources :
+    List Text
+, cc-options :
+    List Text
+, compiler-options :
+    ./CompilerOptions.dhall 
+, cpp-options :
+    List Text
+, default-extensions :
+    List ./Extension.dhall 
+, default-language :
+    Optional ./Language.dhall 
+, extra-framework-dirs :
+    List Text
+, extra-ghci-libraries :
+    List Text
+, extra-lib-dirs :
+    List Text
+, extra-libraries :
+    List Text
+, frameworks :
+    List Text
+, hs-source-dirs :
+    List Text
+, includes :
+    List Text
+, include-dirs :
+    List Text
+, install-includes :
+    List Text
+, js-sources :
+    List Text
+, ld-options :
+    List Text
+, lib-version-linux :
+    Optional ./Version.dhall 
+, mod-def-files :
+    List Text
+, options :
+    List < Standalone : {} >
+, other-extensions :
+    List ./Extension.dhall 
+, other-languages :
+    List ./Language.dhall 
+, other-modules :
+    List Text
+, pkgconfig-depends :
+    List { name : Text, version : ./VersionRange.dhall  }
+, profiling-options :
+    ./CompilerOptions.dhall 
+, shared-options :
+    ./CompilerOptions.dhall 
+, type :
+    < Shared : {} | Static : {} >
+, lib-version-info :
+    Optional { age : Natural, current : Natural, revision : Natural }
+, mixins :
+    List ./Mixin.dhall 
+}
diff --git a/dhall/types/Guarded.dhall b/dhall/types/Guarded.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Guarded.dhall
@@ -0,0 +1,1 @@
+λ(A : Type) → ./Config.dhall  → A
diff --git a/dhall/types/Language.dhall b/dhall/types/Language.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Language.dhall
@@ -0,0 +1,1 @@
+< Haskell2010 : {} | Haskell98 : {} | UnknownLanguage : { _1 : Text } >
diff --git a/dhall/types/Library.dhall b/dhall/types/Library.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Library.dhall
@@ -0,0 +1,65 @@
+{ autogen-modules :
+    List Text
+, build-depends :
+    List ./Dependency.dhall 
+, build-tool-depends :
+    List { component : Text, package : Text, version : ./VersionRange.dhall  }
+, build-tools :
+    List { exe : Text, version : ./VersionRange.dhall  }
+, buildable :
+    Bool
+, c-sources :
+    List Text
+, cc-options :
+    List Text
+, compiler-options :
+    ./CompilerOptions.dhall 
+, cpp-options :
+    List Text
+, default-extensions :
+    List ./Extension.dhall 
+, default-language :
+    Optional ./Language.dhall 
+, exposed-modules :
+    List Text
+, extra-framework-dirs :
+    List Text
+, extra-ghci-libraries :
+    List Text
+, extra-lib-dirs :
+    List Text
+, extra-libraries :
+    List Text
+, frameworks :
+    List Text
+, hs-source-dirs :
+    List Text
+, includes :
+    List Text
+, include-dirs :
+    List Text
+, install-includes :
+    List Text
+, js-sources :
+    List Text
+, ld-options :
+    List Text
+, other-extensions :
+    List ./Extension.dhall 
+, other-languages :
+    List ./Language.dhall 
+, other-modules :
+    List Text
+, pkgconfig-depends :
+    List { name : Text, version : ./VersionRange.dhall  }
+, profiling-options :
+    ./CompilerOptions.dhall 
+, reexported-modules :
+    List { name : Text, original : { name : Text, package : Optional Text } }
+, shared-options :
+    ./CompilerOptions.dhall 
+, mixins :
+    List ./Mixin.dhall 
+, signatures :
+    List Text
+}
diff --git a/dhall/types/License.dhall b/dhall/types/License.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/License.dhall
@@ -0,0 +1,29 @@
+< AGPL :
+    Optional ./Version.dhall 
+| AllRightsReserved :
+    {}
+| Apache :
+    Optional ./Version.dhall 
+| BSD2 :
+    {}
+| BSD3 :
+    {}
+| BSD4 :
+    {}
+| GPL :
+    Optional ./Version.dhall 
+| ISC :
+    {}
+| LGPL :
+    Optional ./Version.dhall 
+| MIT :
+    {}
+| MPL :
+    ./Version.dhall 
+| Other :
+    {}
+| PublicDomain :
+    {}
+| Unspecified :
+    {}
+>
diff --git a/dhall/types/Mixin.dhall b/dhall/types/Mixin.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Mixin.dhall
@@ -0,0 +1,5 @@
+{ package :
+    Text
+, renaming :
+    { provides : ./ModuleRenaming.dhall , requires : ./ModuleRenaming.dhall  }
+}
diff --git a/dhall/types/ModuleRenaming.dhall b/dhall/types/ModuleRenaming.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/ModuleRenaming.dhall
@@ -0,0 +1,1 @@
+List { rename : Text, to : Text }
diff --git a/dhall/types/OS.dhall b/dhall/types/OS.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/OS.dhall
@@ -0,0 +1,35 @@
+< AIX :
+    {}
+| Android :
+    {}
+| DragonFly :
+    {}
+| FreeBSD :
+    {}
+| Ghcjs :
+    {}
+| HPUX :
+    {}
+| HaLVM :
+    {}
+| Hurd :
+    {}
+| IOS :
+    {}
+| IRIX :
+    {}
+| Linux :
+    {}
+| NetBSD :
+    {}
+| OSX :
+    {}
+| OpenBSD :
+    {}
+| OtherOS :
+    { _1 : Text }
+| Solaris :
+    {}
+| Windows :
+    {}
+>
diff --git a/dhall/types/Package.dhall b/dhall/types/Package.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Package.dhall
@@ -0,0 +1,65 @@
+{ author :
+    Text
+, benchmarks :
+    List { benchmark : ./Guarded.dhall  ./Benchmark.dhall , name : Text }
+, bug-reports :
+    Text
+, build-type :
+    Optional ./BuildType.dhall 
+, cabal-version :
+    ./Version.dhall 
+, category :
+    Text
+, copyright :
+    Text
+, custom-setup :
+    Optional ./CustomSetup.dhall 
+, data-dir :
+    Text
+, data-files :
+    List Text
+, description :
+    Text
+, executables :
+    List { executable : ./Guarded.dhall  ./Executable.dhall , name : Text }
+, extra-doc-files :
+    List Text
+, extra-source-files :
+    List Text
+, extra-tmp-files :
+    List Text
+, flags :
+    List { default : Bool, description : Text, manual : Bool, name : Text }
+, foreign-libraries :
+    List { foreign-lib : ./Guarded.dhall  ./ForeignLibrary.dhall , name : Text }
+, homepage :
+    Text
+, library :
+    Optional (./Guarded.dhall  ./Library.dhall )
+, license :
+    ./License.dhall 
+, license-files :
+    List Text
+, maintainer :
+    Text
+, name :
+    Text
+, package-url :
+    Text
+, source-repos :
+    List ./SourceRepo.dhall 
+, stability :
+    Text
+, sub-libraries :
+    List { library : ./Guarded.dhall  ./Library.dhall , name : Text }
+, synopsis :
+    Text
+, test-suites :
+    List { name : Text, test-suite : ./Guarded.dhall  ./TestSuite.dhall  }
+, tested-with :
+    List { compiler : ./Compiler.dhall , version : ./VersionRange.dhall  }
+, version :
+    ./Version.dhall 
+, x-fields :
+    List { _1 : Text, _2 : Text }
+}
diff --git a/dhall/types/RepoKind.dhall b/dhall/types/RepoKind.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/RepoKind.dhall
@@ -0,0 +1,1 @@
+< RepoHead : {} | RepoKindUnknown : { _1 : Text } | RepoThis : {} >
diff --git a/dhall/types/RepoType.dhall b/dhall/types/RepoType.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/RepoType.dhall
@@ -0,0 +1,19 @@
+< Bazaar :
+    {}
+| CVS :
+    {}
+| Darcs :
+    {}
+| Git :
+    {}
+| GnuArch :
+    {}
+| Mercurial :
+    {}
+| Monotone :
+    {}
+| OtherRepoType :
+    { _1 : Text }
+| SVN :
+    {}
+>
diff --git a/dhall/types/Scope.dhall b/dhall/types/Scope.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Scope.dhall
@@ -0,0 +1,1 @@
+< Public : {} | Private : {} >
diff --git a/dhall/types/SetupBuildInfo.dhall b/dhall/types/SetupBuildInfo.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/SetupBuildInfo.dhall
@@ -0,0 +1,1 @@
+{ setup-depends : List ./Dependency.dhall  }
diff --git a/dhall/types/SourceRepo.dhall b/dhall/types/SourceRepo.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/SourceRepo.dhall
@@ -0,0 +1,15 @@
+{ type :
+    Optional ./RepoType.dhall 
+, location :
+    Optional Text
+, module :
+    Optional Text
+, branch :
+    Optional Text
+, tag :
+    Optional Text
+, subdir :
+    Optional Text
+, kind :
+    ./RepoKind.dhall 
+}
diff --git a/dhall/types/TestSuite.dhall b/dhall/types/TestSuite.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/TestSuite.dhall
@@ -0,0 +1,61 @@
+{ autogen-modules :
+    List Text
+, build-depends :
+    List ./Dependency.dhall 
+, build-tool-depends :
+    List { component : Text, package : Text, version : ./VersionRange.dhall  }
+, build-tools :
+    List { exe : Text, version : ./VersionRange.dhall  }
+, buildable :
+    Bool
+, c-sources :
+    List Text
+, cc-options :
+    List Text
+, compiler-options :
+    ./CompilerOptions.dhall 
+, cpp-options :
+    List Text
+, default-extensions :
+    List ./Extension.dhall 
+, default-language :
+    Optional ./Language.dhall 
+, extra-framework-dirs :
+    List Text
+, extra-ghci-libraries :
+    List Text
+, extra-lib-dirs :
+    List Text
+, extra-libraries :
+    List Text
+, frameworks :
+    List Text
+, hs-source-dirs :
+    List Text
+, includes :
+    List Text
+, include-dirs :
+    List Text
+, install-includes :
+    List Text
+, js-sources :
+    List Text
+, ld-options :
+    List Text
+, other-extensions :
+    List ./Extension.dhall 
+, other-languages :
+    List ./Language.dhall 
+, other-modules :
+    List Text
+, pkgconfig-depends :
+    List { name : Text, version : ./VersionRange.dhall  }
+, profiling-options :
+    ./CompilerOptions.dhall 
+, shared-options :
+    ./CompilerOptions.dhall 
+, mixins :
+    List ./Mixin.dhall 
+, type :
+    ./TestType.dhall 
+}
diff --git a/dhall/types/TestType.dhall b/dhall/types/TestType.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/TestType.dhall
@@ -0,0 +1,1 @@
+< exitcode-stdio : { main-is : Text } | detailed : { module : Text } >
diff --git a/dhall/types/Version.dhall b/dhall/types/Version.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Version.dhall
@@ -0,0 +1,1 @@
+∀(Version : Type) → ∀(v : Text → Version) → Version
diff --git a/dhall/types/Version/v.dhall b/dhall/types/Version/v.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/Version/v.dhall
@@ -0,0 +1,5 @@
+    let v
+        : ∀(str : Text) → ../Version.dhall 
+        = λ(str : Text) → λ(Version : Type) → λ(v : Text → Version) → v str
+
+in  v
diff --git a/dhall/types/VersionRange.dhall b/dhall/types/VersionRange.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange.dhall
@@ -0,0 +1,16 @@
+  ∀(VersionRange : Type)
+→ ∀(anyVersion : VersionRange)
+→ ∀(noVersion : VersionRange)
+→ ∀(thisVersion : ./Version.dhall  → VersionRange)
+→ ∀(notThisVersion : ./Version.dhall  → VersionRange)
+→ ∀(laterVersion : ./Version.dhall  → VersionRange)
+→ ∀(earlierVersion : ./Version.dhall  → VersionRange)
+→ ∀(orLaterVersion : ./Version.dhall  → VersionRange)
+→ ∀(orEarlierVersion : ./Version.dhall  → VersionRange)
+→ ∀(withinVersion : ./Version.dhall  → VersionRange)
+→ ∀(majorBoundVersion : ./Version.dhall  → VersionRange)
+→ ∀(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ ∀(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ ∀(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ ∀(invertVersionRange : VersionRange → VersionRange)
+→ VersionRange
diff --git a/dhall/types/VersionRange/AnyVersion.dhall b/dhall/types/VersionRange/AnyVersion.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange/AnyVersion.dhall
@@ -0,0 +1,16 @@
+  λ(VersionRange : Type)
+→ λ(anyVersion : VersionRange)
+→ λ(noVersion : VersionRange)
+→ λ(thisVersion : ../Version.dhall  → VersionRange)
+→ λ(notThisVersion : ../Version.dhall  → VersionRange)
+→ λ(laterVersion : ../Version.dhall  → VersionRange)
+→ λ(earlierVersion : ../Version.dhall  → VersionRange)
+→ λ(orLaterVersion : ../Version.dhall  → VersionRange)
+→ λ(orEarlierVersion : ../Version.dhall  → VersionRange)
+→ λ(withinVersion : ../Version.dhall  → VersionRange)
+→ λ(majorBoundVersion : ../Version.dhall  → VersionRange)
+→ λ(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(invertVersionRange : VersionRange → VersionRange)
+→ anyVersion
diff --git a/dhall/types/VersionRange/DifferenceVersionRanges.dhall b/dhall/types/VersionRange/DifferenceVersionRanges.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange/DifferenceVersionRanges.dhall
@@ -0,0 +1,52 @@
+  λ(a : ../VersionRange.dhall )
+→ λ(b : ../VersionRange.dhall )
+→ λ(VersionRange : Type)
+→ λ(anyVersion : VersionRange)
+→ λ(noVersion : VersionRange)
+→ λ(thisVersion : ../Version.dhall  → VersionRange)
+→ λ(notThisVersion : ../Version.dhall  → VersionRange)
+→ λ(laterVersion : ../Version.dhall  → VersionRange)
+→ λ(earlierVersion : ../Version.dhall  → VersionRange)
+→ λ(orLaterVersion : ../Version.dhall  → VersionRange)
+→ λ(orEarlierVersion : ../Version.dhall  → VersionRange)
+→ λ(withinVersion : ../Version.dhall  → VersionRange)
+→ λ(majorBoundVersion : ../Version.dhall  → VersionRange)
+→ λ(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(invertVersionRange : VersionRange → VersionRange)
+→ DifferenceVersionRanges
+  ( a
+    VersionRange
+    anyVersion
+    noVersion
+    thisVersion
+    notThisVersion
+    laterVersion
+    earlierVersion
+    orLaterVersion
+    orEarlierVersion
+    withinVersion
+    majorBoundVersion
+    unionVersionRanges
+    intersectVersionRanges
+    differenceVersionRanges
+    invertVersionRange
+  )
+  ( b
+    VersionRange
+    anyVersion
+    noVersion
+    thisVersion
+    notThisVersion
+    laterVersion
+    earlierVersion
+    orLaterVersion
+    orEarlierVersion
+    withinVersion
+    majorBoundVersion
+    unionVersionRanges
+    intersectVersionRanges
+    differenceVersionRanges
+    invertVersionRange
+  )
diff --git a/dhall/types/VersionRange/EarlierVersion.dhall b/dhall/types/VersionRange/EarlierVersion.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange/EarlierVersion.dhall
@@ -0,0 +1,17 @@
+  λ(v : ../Version.dhall )
+→ λ(VersionRange : Type)
+→ λ(anyVersion : VersionRange)
+→ λ(noVersion : VersionRange)
+→ λ(thisVersion : ../Version.dhall  → VersionRange)
+→ λ(notThisVersion : ../Version.dhall  → VersionRange)
+→ λ(laterVersion : ../Version.dhall  → VersionRange)
+→ λ(earlierVersion : ../Version.dhall  → VersionRange)
+→ λ(orLaterVersion : ../Version.dhall  → VersionRange)
+→ λ(orEarlierVersion : ../Version.dhall  → VersionRange)
+→ λ(withinVersion : ../Version.dhall  → VersionRange)
+→ λ(majorBoundVersion : ../Version.dhall  → VersionRange)
+→ λ(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(invertVersionRange : VersionRange → VersionRange)
+→ earlierVersion v
diff --git a/dhall/types/VersionRange/IntersectVersionRanges.dhall b/dhall/types/VersionRange/IntersectVersionRanges.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange/IntersectVersionRanges.dhall
@@ -0,0 +1,52 @@
+  λ(a : ../VersionRange.dhall )
+→ λ(b : ../VersionRange.dhall )
+→ λ(VersionRange : Type)
+→ λ(anyVersion : VersionRange)
+→ λ(noVersion : VersionRange)
+→ λ(thisVersion : ../Version.dhall  → VersionRange)
+→ λ(notThisVersion : ../Version.dhall  → VersionRange)
+→ λ(laterVersion : ../Version.dhall  → VersionRange)
+→ λ(earlierVersion : ../Version.dhall  → VersionRange)
+→ λ(orLaterVersion : ../Version.dhall  → VersionRange)
+→ λ(orEarlierVersion : ../Version.dhall  → VersionRange)
+→ λ(withinVersion : ../Version.dhall  → VersionRange)
+→ λ(majorBoundVersion : ../Version.dhall  → VersionRange)
+→ λ(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(invertVersionRange : VersionRange → VersionRange)
+→ intersectVersionRanges
+  ( a
+    VersionRange
+    anyVersion
+    noVersion
+    thisVersion
+    notThisVersion
+    laterVersion
+    earlierVersion
+    orLaterVersion
+    orEarlierVersion
+    withinVersion
+    majorBoundVersion
+    unionVersionRanges
+    intersectVersionRanges
+    differenceVersionRanges
+    invertVersionRange
+  )
+  ( b
+    VersionRange
+    anyVersion
+    noVersion
+    thisVersion
+    notThisVersion
+    laterVersion
+    earlierVersion
+    orLaterVersion
+    orEarlierVersion
+    withinVersion
+    majorBoundVersion
+    unionVersionRanges
+    intersectVersionRanges
+    differenceVersionRanges
+    invertVersionRange
+  )
diff --git a/dhall/types/VersionRange/InvertVersionRange.dhall b/dhall/types/VersionRange/InvertVersionRange.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange/InvertVersionRange.dhall
@@ -0,0 +1,34 @@
+  λ(a : ../VersionRange.dhall )
+→ λ(VersionRange : Type)
+→ λ(anyVersion : VersionRange)
+→ λ(noVersion : VersionRange)
+→ λ(thisVersion : ../Version.dhall  → VersionRange)
+→ λ(notThisVersion : ../Version.dhall  → VersionRange)
+→ λ(laterVersion : ../Version.dhall  → VersionRange)
+→ λ(earlierVersion : ../Version.dhall  → VersionRange)
+→ λ(orLaterVersion : ../Version.dhall  → VersionRange)
+→ λ(orEarlierVersion : ../Version.dhall  → VersionRange)
+→ λ(withinVersion : ../Version.dhall  → VersionRange)
+→ λ(majorBoundVersion : ../Version.dhall  → VersionRange)
+→ λ(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(invertVersionRange : VersionRange → VersionRange)
+→ invertVersionRange
+  ( a
+    VersionRange
+    anyVersion
+    noVersion
+    thisVersion
+    notThisVersion
+    laterVersion
+    earlierVersion
+    orLaterVersion
+    orEarlierVersion
+    withinVersion
+    majorBoundVersion
+    unionVersionRanges
+    intersectVersionRanges
+    differenceVersionRanges
+    invertVersionRange
+  )
diff --git a/dhall/types/VersionRange/LaterVersion.dhall b/dhall/types/VersionRange/LaterVersion.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange/LaterVersion.dhall
@@ -0,0 +1,17 @@
+  λ(v : ../Version.dhall )
+→ λ(VersionRange : Type)
+→ λ(anyVersion : VersionRange)
+→ λ(noVersion : VersionRange)
+→ λ(thisVersion : ../Version.dhall  → VersionRange)
+→ λ(notThisVersion : ../Version.dhall  → VersionRange)
+→ λ(laterVersion : ../Version.dhall  → VersionRange)
+→ λ(earlierVersion : ../Version.dhall  → VersionRange)
+→ λ(orLaterVersion : ../Version.dhall  → VersionRange)
+→ λ(orEarlierVersion : ../Version.dhall  → VersionRange)
+→ λ(withinVersion : ../Version.dhall  → VersionRange)
+→ λ(majorBoundVersion : ../Version.dhall  → VersionRange)
+→ λ(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(invertVersionRange : VersionRange → VersionRange)
+→ laterVersion v
diff --git a/dhall/types/VersionRange/MajorBoundVersion.dhall b/dhall/types/VersionRange/MajorBoundVersion.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange/MajorBoundVersion.dhall
@@ -0,0 +1,17 @@
+  λ(v : ../Version.dhall )
+→ λ(VersionRange : Type)
+→ λ(anyVersion : VersionRange)
+→ λ(noVersion : VersionRange)
+→ λ(thisVersion : ../Version.dhall  → VersionRange)
+→ λ(notThisVersion : ../Version.dhall  → VersionRange)
+→ λ(laterVersion : ../Version.dhall  → VersionRange)
+→ λ(earlierVersion : ../Version.dhall  → VersionRange)
+→ λ(orLaterVersion : ../Version.dhall  → VersionRange)
+→ λ(orEarlierVersion : ../Version.dhall  → VersionRange)
+→ λ(withinVersion : ../Version.dhall  → VersionRange)
+→ λ(majorBoundVersion : ../Version.dhall  → VersionRange)
+→ λ(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(invertVersionRange : VersionRange → VersionRange)
+→ majorBoundVersion v
diff --git a/dhall/types/VersionRange/NoVersion.dhall b/dhall/types/VersionRange/NoVersion.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange/NoVersion.dhall
@@ -0,0 +1,16 @@
+  λ(VersionRange : Type)
+→ λ(anyVersion : VersionRange)
+→ λ(noVersion : VersionRange)
+→ λ(thisVersion : ../Version.dhall  → VersionRange)
+→ λ(notThisVersion : ../Version.dhall  → VersionRange)
+→ λ(laterVersion : ../Version.dhall  → VersionRange)
+→ λ(earlierVersion : ../Version.dhall  → VersionRange)
+→ λ(orLaterVersion : ../Version.dhall  → VersionRange)
+→ λ(orEarlierVersion : ../Version.dhall  → VersionRange)
+→ λ(withinVersion : ../Version.dhall  → VersionRange)
+→ λ(majorBoundVersion : ../Version.dhall  → VersionRange)
+→ λ(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(invertVersionRange : VersionRange → VersionRange)
+→ noVersion
diff --git a/dhall/types/VersionRange/NotThisVersion.dhall b/dhall/types/VersionRange/NotThisVersion.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange/NotThisVersion.dhall
@@ -0,0 +1,17 @@
+  λ(v : ../Version.dhall )
+→ λ(VersionRange : Type)
+→ λ(anyVersion : VersionRange)
+→ λ(noVersion : VersionRange)
+→ λ(thisVersion : ../Version.dhall  → VersionRange)
+→ λ(notThisVersion : ../Version.dhall  → VersionRange)
+→ λ(laterVersion : ../Version.dhall  → VersionRange)
+→ λ(earlierVersion : ../Version.dhall  → VersionRange)
+→ λ(orLaterVersion : ../Version.dhall  → VersionRange)
+→ λ(orEarlierVersion : ../Version.dhall  → VersionRange)
+→ λ(withinVersion : ../Version.dhall  → VersionRange)
+→ λ(majorBoundVersion : ../Version.dhall  → VersionRange)
+→ λ(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(invertVersionRange : VersionRange → VersionRange)
+→ notThisVersion v
diff --git a/dhall/types/VersionRange/OrEarlierVersion.dhall b/dhall/types/VersionRange/OrEarlierVersion.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange/OrEarlierVersion.dhall
@@ -0,0 +1,17 @@
+  λ(v : ../Version.dhall )
+→ λ(VersionRange : Type)
+→ λ(anyVersion : VersionRange)
+→ λ(noVersion : VersionRange)
+→ λ(thisVersion : ../Version.dhall  → VersionRange)
+→ λ(notThisVersion : ../Version.dhall  → VersionRange)
+→ λ(laterVersion : ../Version.dhall  → VersionRange)
+→ λ(earlierVersion : ../Version.dhall  → VersionRange)
+→ λ(orLaterVersion : ../Version.dhall  → VersionRange)
+→ λ(orEarlierVersion : ../Version.dhall  → VersionRange)
+→ λ(withinVersion : ../Version.dhall  → VersionRange)
+→ λ(majorBoundVersion : ../Version.dhall  → VersionRange)
+→ λ(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(invertVersionRange : VersionRange → VersionRange)
+→ orEarlierVersion v
diff --git a/dhall/types/VersionRange/OrLaterVersion.dhall b/dhall/types/VersionRange/OrLaterVersion.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange/OrLaterVersion.dhall
@@ -0,0 +1,17 @@
+  λ(v : ../Version.dhall )
+→ λ(VersionRange : Type)
+→ λ(anyVersion : VersionRange)
+→ λ(noVersion : VersionRange)
+→ λ(thisVersion : ../Version.dhall  → VersionRange)
+→ λ(notThisVersion : ../Version.dhall  → VersionRange)
+→ λ(laterVersion : ../Version.dhall  → VersionRange)
+→ λ(earlierVersion : ../Version.dhall  → VersionRange)
+→ λ(orLaterVersion : ../Version.dhall  → VersionRange)
+→ λ(orEarlierVersion : ../Version.dhall  → VersionRange)
+→ λ(withinVersion : ../Version.dhall  → VersionRange)
+→ λ(majorBoundVersion : ../Version.dhall  → VersionRange)
+→ λ(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(invertVersionRange : VersionRange → VersionRange)
+→ orLaterVersion v
diff --git a/dhall/types/VersionRange/ThisVersion.dhall b/dhall/types/VersionRange/ThisVersion.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange/ThisVersion.dhall
@@ -0,0 +1,17 @@
+  λ(v : ../Version.dhall )
+→ λ(VersionRange : Type)
+→ λ(anyVersion : VersionRange)
+→ λ(noVersion : VersionRange)
+→ λ(thisVersion : ../Version.dhall  → VersionRange)
+→ λ(notThisVersion : ../Version.dhall  → VersionRange)
+→ λ(laterVersion : ../Version.dhall  → VersionRange)
+→ λ(earlierVersion : ../Version.dhall  → VersionRange)
+→ λ(orLaterVersion : ../Version.dhall  → VersionRange)
+→ λ(orEarlierVersion : ../Version.dhall  → VersionRange)
+→ λ(withinVersion : ../Version.dhall  → VersionRange)
+→ λ(majorBoundVersion : ../Version.dhall  → VersionRange)
+→ λ(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(invertVersionRange : VersionRange → VersionRange)
+→ thisVersion v
diff --git a/dhall/types/VersionRange/UnionVersionRanges.dhall b/dhall/types/VersionRange/UnionVersionRanges.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange/UnionVersionRanges.dhall
@@ -0,0 +1,52 @@
+  λ(a : ../VersionRange.dhall )
+→ λ(b : ../VersionRange.dhall )
+→ λ(VersionRange : Type)
+→ λ(anyVersion : VersionRange)
+→ λ(noVersion : VersionRange)
+→ λ(thisVersion : ../Version.dhall  → VersionRange)
+→ λ(notThisVersion : ../Version.dhall  → VersionRange)
+→ λ(laterVersion : ../Version.dhall  → VersionRange)
+→ λ(earlierVersion : ../Version.dhall  → VersionRange)
+→ λ(orLaterVersion : ../Version.dhall  → VersionRange)
+→ λ(orEarlierVersion : ../Version.dhall  → VersionRange)
+→ λ(withinVersion : ../Version.dhall  → VersionRange)
+→ λ(majorBoundVersion : ../Version.dhall  → VersionRange)
+→ λ(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(invertVersionRange : VersionRange → VersionRange)
+→ unionVersionRanges
+  ( a
+    VersionRange
+    anyVersion
+    noVersion
+    thisVersion
+    notThisVersion
+    laterVersion
+    earlierVersion
+    orLaterVersion
+    orEarlierVersion
+    withinVersion
+    majorBoundVersion
+    unionVersionRanges
+    intersectVersionRanges
+    differenceVersionRanges
+    invertVersionRange
+  )
+  ( b
+    VersionRange
+    anyVersion
+    noVersion
+    thisVersion
+    notThisVersion
+    laterVersion
+    earlierVersion
+    orLaterVersion
+    orEarlierVersion
+    withinVersion
+    majorBoundVersion
+    unionVersionRanges
+    intersectVersionRanges
+    differenceVersionRanges
+    invertVersionRange
+  )
diff --git a/dhall/types/VersionRange/WithinVersion.dhall b/dhall/types/VersionRange/WithinVersion.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/VersionRange/WithinVersion.dhall
@@ -0,0 +1,17 @@
+  λ(v : ../Version.dhall )
+→ λ(VersionRange : Type)
+→ λ(anyVersion : VersionRange)
+→ λ(noVersion : VersionRange)
+→ λ(thisVersion : ../Version.dhall  → VersionRange)
+→ λ(notThisVersion : ../Version.dhall  → VersionRange)
+→ λ(laterVersion : ../Version.dhall  → VersionRange)
+→ λ(earlierVersion : ../Version.dhall  → VersionRange)
+→ λ(orLaterVersion : ../Version.dhall  → VersionRange)
+→ λ(orEarlierVersion : ../Version.dhall  → VersionRange)
+→ λ(withinVersion : ../Version.dhall  → VersionRange)
+→ λ(majorBoundVersion : ../Version.dhall  → VersionRange)
+→ λ(unionVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(intersectVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(differenceVersionRanges : VersionRange → VersionRange → VersionRange)
+→ λ(invertVersionRange : VersionRange → VersionRange)
+→ withinVersion v
diff --git a/dhall/types/builtin.dhall b/dhall/types/builtin.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/types/builtin.dhall
@@ -0,0 +1,1 @@
+{ v : Text → List Natural }
diff --git a/dhall/unconditional.dhall b/dhall/unconditional.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/unconditional.dhall
@@ -0,0 +1,44 @@
+    let unconditional
+        : ∀(A : Type) → A → ./types/Guarded.dhall  A
+        = λ(A : Type) → λ(a : A) → λ(_ : ./types/Config.dhall ) → a
+
+in  let executable
+        :   ∀(name : Text)
+          → ∀(executable : ./types/Executable.dhall )
+          → { name :
+                Text
+            , executable :
+                ./types/Guarded.dhall  ./types/Executable.dhall 
+            }
+        =   λ(name : Text)
+          → λ(executable : ./types/Executable.dhall )
+          → { name =
+                name
+            , executable =
+                unconditional ./types/Executable.dhall  executable
+            }
+
+in  let library
+        :   ∀(library : ./types/Library.dhall )
+          → Optional (./types/Guarded.dhall  ./types/Library.dhall )
+        =   λ(library : ./types/Library.dhall )
+          → [ unconditional ./types/Library.dhall  library
+            ] : Optional (./types/Guarded.dhall  ./types/Library.dhall )
+
+in  let test-suite
+        :   ∀(name : Text)
+          → ∀(test-suite : ./types/TestSuite.dhall )
+          → { name :
+                Text
+            , test-suite :
+                ./types/Guarded.dhall  ./types/TestSuite.dhall 
+            }
+        =   λ(name : Text)
+          → λ(test-suite : ./types/TestSuite.dhall )
+          → { name =
+                name
+            , test-suite =
+                unconditional ./types/TestSuite.dhall  test-suite
+            }
+
+in  { executable = executable, library = library, test-suite = test-suite }
diff --git a/exe/Main.hs b/exe/Main.hs
new file mode 100644
--- /dev/null
+++ b/exe/Main.hs
@@ -0,0 +1,439 @@
+{-# language GeneralizedNewtypeDeriving #-}
+{-# language NoMonomorphismRestriction #-}
+{-# language NamedFieldPuns #-}
+{-# language OverloadedStrings #-}
+
+module Main ( main ) where
+
+import Control.Applicative ( (<**>), (<|>), Const(..), optional )
+import Data.Foldable ( asum, foldl' )
+import Data.Functor.Product ( Product(..) )
+import Data.Functor.Identity ( Identity(..) )
+import Data.Monoid ( Any(..), (<>) )
+import Data.Function ( (&) )
+import Data.Maybe ( fromMaybe )
+import Data.Text.Lazy (Text)
+import System.Environment ( getArgs )
+import Data.String ( fromString )
+
+import DhallToCabal
+
+import qualified Data.Text.Lazy.IO as LazyText
+import qualified Data.Text.Prettyprint.Doc as Pretty
+import qualified Data.Text.Prettyprint.Doc.Render.Text as Pretty
+import qualified Data.Text.Prettyprint.Doc.Symbols.Unicode as Pretty
+import qualified Dhall
+import qualified Dhall.Context
+import qualified Dhall.Core as Dhall
+import qualified Dhall.Core as Expr ( Expr(..), Var(..), shift )
+import qualified Distribution.PackageDescription.PrettyPrint as Cabal
+import qualified Options.Applicative as OptParse
+import qualified System.IO
+
+
+
+data Command
+  = RunDhallToCabal DhallToCabalOptions
+  | PrintType KnownType
+
+
+
+data KnownType
+  = Library
+  | ForeignLibrary
+  | Executable
+  | Benchmark
+  | TestSuite
+  | Config
+  | SourceRepo
+  | RepoType
+  | RepoKind
+  | Compiler
+  | OS
+  | Extension
+  | CompilerOptions
+  | Arch
+  | Language
+  | License
+  | BuildType
+  | Package
+  | VersionRange
+  | Version
+  deriving (Bounded, Enum, Eq, Ord, Read, Show)
+
+
+
+data DhallToCabalOptions = DhallToCabalOptions
+  { dhallFilePath :: Maybe String
+  , explain :: Bool
+  }
+
+
+
+dhallToCabalOptionsParser :: OptParse.Parser DhallToCabalOptions
+dhallToCabalOptionsParser =
+  DhallToCabalOptions
+    <$>
+      optional
+        ( OptParse.argument
+            OptParse.str
+            ( mconcat
+                [ OptParse.metavar "<dhall input file>"
+                , OptParse.help "The Dhall expression to convert to a Cabal file"
+                ]
+            )
+        )
+    <*>
+      OptParse.flag
+        False
+        True
+        ( mconcat
+            [ OptParse.long "explain"
+            , OptParse.help "Provide explanations to type Dhall syntax and type errors."
+            ]
+        )
+
+
+
+printTypeParser :: OptParse.Parser KnownType
+printTypeParser =
+  OptParse.option OptParse.auto modifiers
+
+  where
+
+    modifiers =
+      mconcat
+        [ OptParse.long "print-type"
+        , OptParse.help "Print out the description of a type. For a full description, try --print-type Package"
+        , OptParse.metavar "TYPE"
+        ]
+
+
+
+runDhallToCabal :: DhallToCabalOptions -> IO ()
+runDhallToCabal DhallToCabalOptions { dhallFilePath, explain } = do
+  source <-
+    case dhallFilePath of
+      Nothing ->
+        LazyText.getContents
+
+      Just filePath ->
+        LazyText.readFile filePath
+
+  let
+    fileName = fromMaybe "(STDIN)" dhallFilePath
+
+  explaining
+    ( dhallToCabal fileName source
+        & fmap Cabal.showGenericPackageDescription
+        >>= putStrLn
+    )
+
+  where
+
+    explaining =
+      if explain then Dhall.detailed else id
+
+
+
+main :: IO ()
+main = do
+  command <-
+    OptParse.execParser opts
+
+  case command of
+    RunDhallToCabal options ->
+      runDhallToCabal options
+
+    PrintType t ->
+      printType t
+
+  where
+
+  parser =
+    asum
+      [ RunDhallToCabal <$> dhallToCabalOptionsParser
+      , PrintType <$> printTypeParser
+      ]
+
+  opts =
+    OptParse.info ( parser <**> OptParse.helper ) modifiers
+
+  modifiers =
+    mconcat
+      [ OptParse.progDesc "Generate Cabal files from Dhall expressions"
+      ]
+
+
+
+-- Shamelessly taken from dhall-format
+
+opts :: Pretty.LayoutOptions
+opts =
+  Pretty.defaultLayoutOptions
+    { Pretty.layoutPageWidth = Pretty.AvailablePerLine 80 1.0 }
+
+
+
+printType :: KnownType -> IO ()
+printType t = do
+  Pretty.renderIO
+    System.IO.stdout
+    ( Pretty.layoutSmart opts
+        ( Pretty.pretty factoredType )
+    )
+
+  putStrLn ""
+
+  where
+
+    dhallType t =
+      case t of
+        Config -> configRecordType
+        Library -> Dhall.expected library
+        ForeignLibrary -> Dhall.expected foreignLib
+        Executable -> Dhall.expected executable
+        Benchmark -> Dhall.expected benchmark
+        TestSuite -> Dhall.expected testSuite
+        SourceRepo -> Dhall.expected sourceRepo
+        RepoType -> Dhall.expected repoType
+        RepoKind -> Dhall.expected repoKind
+        Compiler -> Dhall.expected compilerFlavor
+        OS -> Dhall.expected operatingSystem
+        Extension -> Dhall.expected extension
+        CompilerOptions -> Dhall.expected compilerOptions
+        Arch -> Dhall.expected arch
+        Language -> Dhall.expected language
+        License -> Dhall.expected license
+        BuildType -> Dhall.expected buildType
+        Package -> Dhall.expected genericPackageDescription
+        VersionRange -> Dhall.expected versionRange
+        Version -> Dhall.expected version
+
+    letDhallType t =
+      liftCSE ( fromString ( show t ) ) ( dhallType t )
+
+    factoredType =
+      foldl'
+        ( flip letDhallType )
+        ( dhallType t )
+        [ minBound .. maxBound ]
+
+
+liftCSE
+  :: (Eq s, Eq a)
+  => Text          -- ^ The name of the binding
+  -> Expr.Expr s a -- ^ The common subexpression to lift
+  -> Expr.Expr s a -- ^ The expression to remove a common subexpression from
+  -> Expr.Expr s a
+liftCSE name body expr =
+  let
+    v0 =
+      Expr.V name 0
+
+  in
+    case go ( Expr.shift 1 v0 expr ) v0 of
+      Pair ( Const ( Any False ) ) _ ->
+        -- There was nothing to lift
+        expr
+
+      Pair _ ( Identity reduced ) ->
+        -- We did manage to lift a CSE, so let bind it
+        Expr.Let name Nothing body reduced
+
+  where
+
+    shiftName n v | n == name =
+      shiftVar 1 v
+
+    shiftName _ v =
+        v
+
+    shiftVar delta ( Expr.V name' n ) =
+      Expr.V name' ( n + delta )
+
+    go e v | e == body =
+      Pair ( Const ( Any True ) ) ( Identity ( Expr.Var v ) )
+
+    go e v =
+      case e of
+        Expr.Lam n t b ->
+          Expr.Lam n t <$> go b ( shiftName n v )
+
+        Expr.Pi n t b ->
+          Expr.Pi n <$> go t v <*> go b ( shiftName n v )
+
+        Expr.App f a ->
+          Expr.App <$> go f v <*> go a v
+
+        Expr.Let n t b e ->
+          Expr.Let n t <$> go b v <*> go e ( shiftName n v )
+
+        Expr.Annot a b ->
+          Expr.Annot <$> go a v <*> go b v
+
+        Expr.BoolAnd a b ->
+          Expr.BoolAnd <$> go a v <*> go b v
+
+        Expr.BoolOr a b ->
+          Expr.BoolOr <$> go a v <*> go b v
+
+        Expr.BoolEQ a b ->
+          Expr.BoolEQ <$> go a v <*> go b v
+
+        Expr.BoolNE a b ->
+          Expr.BoolNE <$> go a v <*> go b v
+
+        Expr.BoolIf a b c ->
+          Expr.BoolIf <$> go a v <*> go b v <*> go c v
+
+        Expr.NaturalPlus a b ->
+          Expr.NaturalPlus <$> go a v <*> go b v
+
+        Expr.NaturalTimes a b ->
+          Expr.NaturalTimes <$> go a v <*> go b v
+
+        Expr.ListAppend a b ->
+          Expr.ListAppend <$> go a v <*> go b v
+
+        Expr.Combine a b ->
+          Expr.Combine <$> go a v <*> go b v
+
+        Expr.Prefer a b ->
+          Expr.Prefer <$> go a v <*> go b v
+
+        Expr.TextAppend a b ->
+          Expr.TextAppend <$> go a v <*> go b v
+
+        Expr.ListLit t elems ->
+          Expr.ListLit
+            <$> ( traverse ( `go` v ) t )
+            <*> ( traverse ( `go` v ) elems )
+
+        Expr.OptionalLit t elems ->
+          Expr.OptionalLit
+            <$> go t v
+            <*> ( traverse ( `go` v ) elems )
+
+        Expr.Record fields ->
+          Expr.Record <$> traverse ( `go` v ) fields
+
+        Expr.RecordLit fields ->
+          Expr.RecordLit <$> traverse ( `go` v ) fields
+
+        Expr.Union fields ->
+          Expr.Union <$> traverse ( `go` v ) fields
+
+        Expr.UnionLit n a fields ->
+          Expr.UnionLit n <$> go a v <*> traverse ( `go` v ) fields
+
+        Expr.Merge a b t ->
+          Expr.Merge <$> go a v <*> go b v <*> traverse ( `go` v ) t
+
+        Expr.Constructors e ->
+          Expr.Constructors <$> go e v
+
+        Expr.Field e f ->
+          Expr.Field <$> go e v <*> pure f
+
+        Expr.Note s e ->
+          Expr.Note s <$> go e v
+
+        Expr.Embed{} ->
+          pure e
+
+        Expr.Const{} ->
+          pure e
+
+        Expr.Var{} ->
+          pure e
+
+        Expr.Bool{} ->
+          pure e
+
+        Expr.BoolLit{} ->
+          pure e
+
+        Expr.Natural{} ->
+          pure e
+
+        Expr.NaturalLit{} ->
+          pure e
+
+        Expr.NaturalFold{} ->
+          pure e
+
+        Expr.NaturalBuild{} ->
+          pure e
+
+        Expr.NaturalIsZero{} ->
+          pure e
+
+        Expr.NaturalEven{} ->
+          pure e
+
+        Expr.NaturalOdd{} ->
+          pure e
+
+        Expr.NaturalToInteger{} ->
+          pure e
+
+        Expr.NaturalShow{} ->
+          pure e
+
+        Expr.Integer{} ->
+          pure e
+
+        Expr.IntegerShow{} ->
+          pure e
+
+        Expr.IntegerLit{} ->
+          pure e
+
+        Expr.Double{} ->
+          pure e
+
+        Expr.DoubleShow{} ->
+          pure e
+
+        Expr.DoubleLit{} ->
+          pure e
+
+        Expr.Text{} ->
+          pure e
+
+        Expr.TextLit{} ->
+          pure e
+
+        Expr.List ->
+          pure e
+
+        Expr.ListBuild ->
+          pure e
+
+        Expr.ListFold ->
+          pure e
+
+        Expr.ListLength ->
+          pure e
+
+        Expr.ListHead ->
+          pure e
+
+        Expr.ListLast ->
+          pure e
+
+        Expr.ListIndexed ->
+          pure e
+
+        Expr.ListReverse ->
+          pure e
+
+        Expr.Optional ->
+          pure e
+
+        Expr.OptionalFold ->
+          pure e
+
+        Expr.OptionalBuild ->
+          pure e
diff --git a/golden-tests/GoldenTests.hs b/golden-tests/GoldenTests.hs
new file mode 100644
--- /dev/null
+++ b/golden-tests/GoldenTests.hs
@@ -0,0 +1,56 @@
+module Main ( main ) where
+
+import Data.Algorithm.Diff
+import Data.Algorithm.DiffOutput
+import Data.Function ( on )
+import System.FilePath ( takeBaseName, replaceExtension )
+import Test.Tasty ( defaultMain, TestTree, testGroup )
+import Test.Tasty.Golden ( findByExtension )
+import Test.Tasty.Golden.Advanced ( goldenTest )
+
+import qualified Data.ByteString.Lazy as LBS
+import qualified Data.Text.Lazy as LazyText
+import qualified Data.Text.Lazy.Encoding as LazyText
+import qualified Distribution.PackageDescription.Configuration as Cabal
+import qualified Distribution.PackageDescription.Parse as Cabal
+import qualified Distribution.PackageDescription.PrettyPrint as Cabal
+import qualified Distribution.PackageDescription as Cabal
+import qualified Distribution.Verbosity as Cabal
+
+import Distribution.Package.Dhall ( dhallFileToCabal )
+
+
+  
+main :: IO ()
+main =
+  defaultMain =<< goldenTests
+
+
+
+goldenTests :: IO TestTree
+goldenTests = do
+  dhallFiles <-
+    findByExtension [ ".dhall" ] "golden-tests"
+
+  return
+    $ testGroup "dhall-to-cabal golden tests"
+        [ goldenTest
+            ( takeBaseName dhallFile )
+            ( Cabal.readGenericPackageDescription Cabal.normal cabalFile )
+            ( dhallFileToCabal dhallFile )
+            ( \expected actual ->
+                return $
+                  if on (==) Cabal.showGenericPackageDescription expected actual then
+                    Nothing
+                  else
+                    Just "Generated .cabal file does not match input"
+            )
+            ( Cabal.writeGenericPackageDescription cabalFile )
+        | dhallFile <- dhallFiles
+        , let cabalFile = replaceExtension dhallFile ".cabal"
+        ]
+
+
+
+reverseArtifacts pkg =
+  pkg { Cabal.executables = reverse (Cabal.executables pkg) }
diff --git a/lib/Dhall/Extra.hs b/lib/Dhall/Extra.hs
new file mode 100644
--- /dev/null
+++ b/lib/Dhall/Extra.hs
@@ -0,0 +1,129 @@
+{-# language ApplicativeDo #-}
+{-# language GADTs #-}
+{-# language GeneralizedNewtypeDeriving #-}
+{-# language LambdaCase #-}
+{-# language RecordWildCards #-}
+
+module Dhall.Extra
+  ( RecordBuilder
+  , keyValue
+  , makeRecord
+  , makeUnion
+  , validateType
+  , sortExpr
+  )
+  where
+
+import Control.Applicative ( Const(..) )
+import Control.Monad ( join )
+import Control.Monad.Trans.Reader ( Reader, reader, runReader )
+import Data.Functor.Compose ( Compose(..) )
+import Data.Functor.Product ( Product(..) )
+import Data.Hashable ( Hashable )
+import Data.List ( sortBy )
+import Data.Ord ( comparing )
+
+import qualified Data.HashMap.Strict.InsOrd as Map
+import qualified Data.Text.Lazy as LazyText
+import qualified Dhall
+import qualified Dhall.Core as Dhall ( Expr )
+import qualified Dhall.Core as Expr ( Expr(..) )
+import qualified Dhall.Parser
+import qualified Dhall.TypeCheck 
+
+
+
+newtype RecordBuilder a =
+  RecordBuilder
+    ( Product
+        ( Const
+            ( Map.InsOrdHashMap
+                LazyText.Text
+                ( Dhall.Expr Dhall.Parser.Src Dhall.TypeCheck.X )
+            )
+        )
+        ( Compose
+            ( Reader
+                ( Dhall.Expr Dhall.Parser.Src Dhall.TypeCheck.X )
+            )
+            Maybe
+        )
+        a
+    )
+  deriving (Functor, Applicative)
+
+
+
+makeRecord :: RecordBuilder a -> Dhall.Type a
+makeRecord ( RecordBuilder ( Pair ( Const fields ) ( Compose extractF ) ) ) =
+  let
+    extract =
+      runReader extractF
+
+    expected =
+      sortExpr ( Expr.Record fields )
+
+  in Dhall.Type { .. }
+
+
+
+keyValue :: LazyText.Text -> Dhall.Type a -> RecordBuilder a
+keyValue key valueType =
+  let
+    extract expr = do
+      Expr.RecordLit fields <-
+        return expr
+
+      Map.lookup key fields >>= Dhall.extract valueType
+
+  in
+    RecordBuilder
+      ( Pair
+          ( Const ( Map.singleton key ( Dhall.expected valueType ) ) )
+          ( Compose ( reader extract ) )
+      )
+
+
+
+makeUnion :: Map.InsOrdHashMap LazyText.Text ( Dhall.Type a ) -> Dhall.Type a
+makeUnion alts =
+  let
+    extract expr = do
+      Expr.UnionLit ctor v _ <-
+        return expr
+
+      t <-
+        Map.lookup ctor alts
+
+      Dhall.extract t v
+
+    expected =
+      sortExpr ( Expr.Union ( Dhall.expected <$> alts ) )
+
+  in Dhall.Type { .. }
+
+
+
+validateType :: Dhall.Type ( Maybe a ) -> Dhall.Type a
+validateType a =
+  a { Dhall.extract = join . Dhall.extract a }
+
+
+sortInsOrdHashMap :: ( Hashable k, Ord k ) => Map.InsOrdHashMap k v -> Map.InsOrdHashMap k v
+sortInsOrdHashMap =
+  Map.fromList . sortBy ( comparing fst ) . Map.toList
+
+
+sortExpr :: Dhall.Expr s a -> Dhall.Expr s a
+sortExpr = \case
+  Expr.RecordLit r ->
+    Expr.RecordLit ( sortInsOrdHashMap r )
+
+  Expr.Record r ->
+    Expr.Record ( sortInsOrdHashMap r )
+
+  Expr.Union r ->
+    Expr.Union ( sortInsOrdHashMap r )
+
+  e ->
+    e
diff --git a/lib/DhallToCabal.hs b/lib/DhallToCabal.hs
new file mode 100644
--- /dev/null
+++ b/lib/DhallToCabal.hs
@@ -0,0 +1,1251 @@
+{-# language ApplicativeDo #-}
+{-# language FlexibleContexts #-}
+{-# language FlexibleInstances #-}
+{-# language GADTs #-}
+{-# language LambdaCase #-}
+{-# language OverloadedStrings #-}
+{-# language PatternSynonyms #-}
+{-# language RecordWildCards #-}
+
+module DhallToCabal
+  ( dhallToCabal
+  , genericPackageDescription
+  , sourceRepo
+  , repoKind
+  , repoType
+  , compiler
+  , operatingSystem
+  , library
+  , extension
+  , compilerOptions
+  , guarded
+  , arch
+  , compilerFlavor
+  , language
+  , license
+  , executable
+  , testSuite
+  , benchmark
+  , foreignLib
+  , buildType
+  , versionRange
+  , version
+  , configRecordType
+
+  , sortExpr
+  ) where
+
+import Control.Exception ( Exception, throwIO )
+import Data.Function ( (&) )
+import Data.List ( partition )
+import Data.Maybe ( fromMaybe )
+import Data.Monoid ( (<>) )
+import Formatting.Buildable ( Buildable(..) )
+import Text.Trifecta.Delta ( Delta(..) )
+
+import qualified Data.ByteString.Lazy as LazyByteString
+import qualified Data.HashMap.Strict.InsOrd as Map
+import qualified Data.Text as StrictText
+import qualified Data.Text.Encoding as StrictText
+import qualified Data.Text.Lazy as LazyText
+import qualified Data.Text.Lazy.Builder as Builder
+import qualified Data.Text.Lazy.Encoding as LazyText
+import qualified Dhall
+import qualified Dhall.Core
+import qualified Dhall.Import
+import qualified Dhall.Parser
+import qualified Dhall.TypeCheck
+import qualified Distribution.Compiler as Cabal
+import qualified Distribution.License as Cabal
+import qualified Distribution.ModuleName as Cabal
+import qualified Distribution.PackageDescription as Cabal
+import qualified Distribution.System as Cabal ( Arch(..), OS(..) )
+import qualified Distribution.Text as Cabal ( simpleParse )
+import qualified Distribution.Types.CondTree as Cabal
+import qualified Distribution.Types.Dependency as Cabal
+import qualified Distribution.Types.ExeDependency as Cabal
+import qualified Distribution.Types.ExecutableScope as Cabal
+import qualified Distribution.Types.ForeignLib as Cabal
+import qualified Distribution.Types.ForeignLibOption as Cabal
+import qualified Distribution.Types.ForeignLibType as Cabal
+import qualified Distribution.Types.IncludeRenaming as Cabal
+import qualified Distribution.Types.LegacyExeDependency as Cabal
+import qualified Distribution.Types.Mixin as Cabal
+import qualified Distribution.Types.PackageId as Cabal
+import qualified Distribution.Types.PackageName as Cabal
+import qualified Distribution.Types.PkgconfigDependency as Cabal
+import qualified Distribution.Types.PkgconfigName as Cabal
+import qualified Distribution.Types.UnqualComponentName as Cabal
+import qualified Distribution.Version as Cabal
+import qualified Language.Haskell.Extension as Cabal
+
+import qualified Dhall.Core as Expr
+  ( Chunks(..), Const(..), Expr(..), Var(..) )
+
+import Dhall.Extra
+import DhallToCabal.ConfigTree ( ConfigTree(..), toConfigTree )
+import DhallToCabal.Diff ( Diffable(..)  )
+
+
+
+packageIdentifier :: RecordBuilder Cabal.PackageIdentifier
+packageIdentifier = do
+  pkgName <-
+    keyValue "name" packageName
+
+  pkgVersion <-
+    keyValue "version" version
+
+  pure Cabal.PackageIdentifier { .. }
+
+
+
+packageName :: Dhall.Type Cabal.PackageName
+packageName =
+  Cabal.mkPackageName <$> Dhall.string
+
+
+
+packageDescription :: RecordBuilder Cabal.PackageDescription
+packageDescription = do
+  package <-
+    packageIdentifier
+
+  benchmarks <-
+    pure []
+
+  testSuites <-
+    pure []
+
+  executables <-
+    pure []
+
+  foreignLibs <-
+    pure []
+
+  subLibraries <-
+    pure []
+
+  library <-
+    pure Nothing
+
+  customFieldsPD <-
+    keyValue
+      "x-fields"
+      ( Dhall.list ( Dhall.pair Dhall.string Dhall.string ) )
+
+  sourceRepos <-
+    keyValue "source-repos" ( Dhall.list sourceRepo )
+
+  specVersionRaw <-
+    Left <$> keyValue "cabal-version" version
+
+  buildType <-
+    keyValue "build-type" ( Dhall.maybe buildType )
+
+  license <-
+    keyValue "license" license
+
+  licenseFiles <-
+    keyValue "license-files" ( Dhall.list Dhall.string )
+
+  copyright <-
+    keyValue "copyright" Dhall.string
+
+  maintainer <-
+    keyValue "maintainer" Dhall.string
+
+  author <-
+    keyValue "author" Dhall.string
+
+  stability <-
+    keyValue "stability" Dhall.string
+
+  testedWith <-
+    keyValue "tested-with" ( Dhall.list compiler )
+
+  homepage <-
+    keyValue "homepage" Dhall.string
+
+  pkgUrl <-
+    keyValue "package-url" Dhall.string
+
+  bugReports <-
+    keyValue "bug-reports" Dhall.string
+
+  synopsis <-
+    keyValue "synopsis" Dhall.string
+
+  description <-
+    keyValue "description" Dhall.string
+
+  category <-
+    keyValue "category" Dhall.string
+
+  -- Cabal documentation states
+  --
+  --   > YOU PROBABLY DON'T WANT TO USE THIS FIELD.
+  --
+  -- So I guess we won't use this field.
+  buildDepends <-
+    pure []
+
+  setupBuildInfo <-
+    keyValue "custom-setup" ( Dhall.maybe setupBuildInfo )
+
+  dataFiles <-
+    keyValue "data-files" ( Dhall.list Dhall.string )
+
+  dataDir <-
+    keyValue "data-dir" Dhall.string
+
+  extraSrcFiles <-
+    keyValue "extra-source-files" ( Dhall.list Dhall.string )
+
+  extraTmpFiles <-
+    keyValue "extra-tmp-files" ( Dhall.list Dhall.string )
+
+  extraDocFiles <-
+    keyValue "extra-doc-files" ( Dhall.list Dhall.string )
+
+  return Cabal.PackageDescription { .. }
+
+
+
+version :: Dhall.Type Cabal.Version
+version =
+  let
+    parse builder =
+      fromMaybe
+        ( error "Could not parse version" )
+        ( Cabal.simpleParse ( LazyText.unpack ( Builder.toLazyText builder ) ) )
+
+    extract =
+      \case
+        LamArr _Version (LamArr _v v) ->
+          go v
+
+        e ->
+          error ( show e )
+
+    go =
+      \case
+        Expr.App ( V0 "v" ) ( Expr.TextLit ( Expr.Chunks [] builder ) ) ->
+          return ( parse builder )
+
+        e ->
+          error ( show e )
+
+    expected =
+      Expr.Pi "Version" ( Expr.Const Expr.Type )
+        $ Expr.Pi
+            "v"
+            ( Expr.Pi "_" ( Dhall.expected Dhall.string ) ( V0 "Version" ) )
+            ( V0 "Version" )
+
+  in Dhall.Type { .. }
+
+
+
+benchmark :: Dhall.Type Cabal.Benchmark
+benchmark =
+  makeRecord $ do
+    mainIs <-
+      keyValue "main-is" Dhall.string
+
+    benchmarkName <-
+      pure ""
+
+    benchmarkBuildInfo <-
+      buildInfo
+
+    pure
+      Cabal.Benchmark
+        { benchmarkInterface =
+            Cabal.BenchmarkExeV10 ( Cabal.mkVersion [ 1, 0 ] ) mainIs
+        , ..
+        }
+
+
+
+buildInfo :: RecordBuilder Cabal.BuildInfo
+buildInfo = do
+  buildable <-
+    keyValue "buildable" Dhall.bool
+
+  buildTools <-
+    keyValue "build-tools" ( Dhall.list legacyExeDependency )
+
+  buildToolDepends <-
+    keyValue "build-tool-depends" ( Dhall.list exeDependency )
+
+  cppOptions <-
+    keyValue "cpp-options" ( Dhall.list Dhall.string )
+
+  ccOptions <-
+    keyValue "cc-options" ( Dhall.list Dhall.string )
+
+  ldOptions <-
+    keyValue "ld-options" ( Dhall.list Dhall.string )
+
+  pkgconfigDepends <-
+    keyValue "pkgconfig-depends" ( Dhall.list pkgconfigDependency )
+
+  frameworks <-
+    keyValue "frameworks" ( Dhall.list Dhall.string )
+
+  extraFrameworkDirs <-
+    keyValue "extra-framework-dirs" ( Dhall.list Dhall.string )
+
+  cSources <-
+    keyValue "c-sources" ( Dhall.list Dhall.string )
+
+  jsSources <-
+    keyValue "js-sources" ( Dhall.list Dhall.string )
+
+  hsSourceDirs <-
+    keyValue "hs-source-dirs" ( Dhall.list Dhall.string )
+
+  otherModules <-
+    keyValue "other-modules" ( Dhall.list moduleName )
+
+  autogenModules <-
+    keyValue "autogen-modules" ( Dhall.list moduleName )
+
+  defaultLanguage <-
+    keyValue "default-language" ( Dhall.maybe language )
+
+  otherLanguages <-
+    keyValue "other-languages" ( Dhall.list language )
+
+  defaultExtensions <-
+    keyValue "default-extensions" ( Dhall.list extension )
+
+  otherExtensions <-
+    keyValue "other-extensions" ( Dhall.list extension )
+
+  oldExtensions <-
+    pure []
+
+  extraLibs <-
+    keyValue "extra-libraries" ( Dhall.list Dhall.string )
+
+  extraGHCiLibs <-
+    keyValue "extra-ghci-libraries" ( Dhall.list Dhall.string )
+
+  extraLibDirs <-
+    keyValue "extra-lib-dirs" ( Dhall.list Dhall.string )
+
+  includeDirs <-
+    keyValue "include-dirs" ( Dhall.list Dhall.string )
+
+  includes <-
+    keyValue "includes" ( Dhall.list Dhall.string )
+
+  installIncludes <-
+    keyValue "install-includes" ( Dhall.list Dhall.string )
+
+  options <-
+    keyValue "compiler-options" compilerOptions
+
+  profOptions <-
+    keyValue "profiling-options" compilerOptions
+
+  sharedOptions <-
+    keyValue "shared-options" compilerOptions
+
+  customFieldsBI <-
+    pure []
+
+  targetBuildDepends <-
+    keyValue "build-depends" ( Dhall.list dependency )
+
+  mixins <-
+    keyValue "mixins" ( Dhall.list mixin )
+
+  return Cabal.BuildInfo { ..  }
+
+
+
+testSuite :: Dhall.Type Cabal.TestSuite
+testSuite =
+  makeRecord $ do
+    testName <-
+      pure ""
+
+    testBuildInfo <-
+      buildInfo
+
+    testInterface <-
+      keyValue "type" testSuiteInterface
+
+    pure
+      Cabal.TestSuite
+        { ..
+        }
+
+
+
+testSuiteInterface :: Dhall.Type Cabal.TestSuiteInterface
+testSuiteInterface =
+  makeUnion
+    ( Map.fromList
+        [ ( "exitcode-stdio"
+          , Cabal.TestSuiteExeV10 ( Cabal.mkVersion [ 1, 0 ] )
+              <$> makeRecord ( keyValue "main-is" Dhall.string )
+          )
+        , ( "detailed"
+          , Cabal.TestSuiteLibV09 ( Cabal.mkVersion [ 0, 9 ] )
+              <$> makeRecord ( keyValue "module" moduleName )
+          )
+        ]
+    )
+
+
+
+
+unqualComponentName :: Dhall.Type Cabal.UnqualComponentName
+unqualComponentName =
+  Cabal.mkUnqualComponentName <$> Dhall.string
+
+
+
+executable :: Dhall.Type Cabal.Executable
+executable =
+  makeRecord $ do
+    exeName <-
+      pure ""
+
+    modulePath <-
+      keyValue "main-is" Dhall.string
+
+    exeScope <-
+      keyValue "scope" executableScope
+
+    buildInfo <-
+      buildInfo
+
+    pure Cabal.Executable { .. }
+
+
+
+foreignLib :: Dhall.Type Cabal.ForeignLib
+foreignLib =
+  makeRecord $ do
+    foreignLibName <-
+      pure ""
+
+    foreignLibType <-
+      keyValue "type" foreignLibType
+
+    foreignLibOptions <-
+      keyValue "options" ( Dhall.list foreignLibOption )
+
+    foreignLibBuildInfo <-
+      buildInfo
+
+    foreignLibVersionInfo <-
+      keyValue "lib-version-info" ( Dhall.maybe versionInfo )
+
+    foreignLibVersionLinux <-
+      keyValue "lib-version-linux" ( Dhall.maybe version )
+
+    foreignLibModDefFile <-
+      keyValue "mod-def-files" ( Dhall.list Dhall.string )
+
+    pure Cabal.ForeignLib { .. }
+
+
+
+foreignLibType :: Dhall.Type Cabal.ForeignLibType
+foreignLibType =
+  makeUnion
+    ( Map.fromList
+        [ ( "Shared", Cabal.ForeignLibNativeShared <$ Dhall.unit )
+        , ( "Static", Cabal.ForeignLibNativeStatic <$ Dhall.unit )
+        ]
+    )
+
+
+
+library :: Dhall.Type Cabal.Library
+library =
+  makeRecord $ do
+    libName <-
+      pure Nothing
+
+    libBuildInfo <-
+      buildInfo
+
+    exposedModules <-
+      keyValue "exposed-modules" ( Dhall.list moduleName )
+
+    reexportedModules <-
+      keyValue "reexported-modules" ( Dhall.list moduleReexport )
+
+    signatures <-
+      keyValue "signatures" ( Dhall.list moduleName )
+
+    libExposed <-
+      pure True
+
+    pure Cabal.Library { .. }
+
+
+
+sourceRepo :: Dhall.Type Cabal.SourceRepo
+sourceRepo =
+  makeRecord $ do
+    repoKind <-
+      keyValue "kind" repoKind
+
+    repoType <-
+      keyValue "type" ( Dhall.maybe repoType )
+
+    repoLocation <-
+      keyValue "location" ( Dhall.maybe Dhall.string )
+
+    repoModule <-
+      keyValue "module" ( Dhall.maybe Dhall.string )
+
+    repoBranch <-
+      keyValue "branch" ( Dhall.maybe Dhall.string )
+
+    repoTag <-
+      keyValue "tag" ( Dhall.maybe Dhall.string )
+
+    repoSubdir <-
+      keyValue "subdir" ( Dhall.maybe filePath )
+
+    pure Cabal.SourceRepo { .. }
+
+
+
+repoKind :: Dhall.Type Cabal.RepoKind
+repoKind =
+  sortType Dhall.genericAuto
+
+
+
+dependency :: Dhall.Type Cabal.Dependency
+dependency =
+  makeRecord $ do
+    packageName <-
+      keyValue "package" packageName
+
+    versionRange <-
+      keyValue "bounds" versionRange
+
+    pure ( Cabal.Dependency packageName versionRange )
+
+
+
+moduleName :: Dhall.Type Cabal.ModuleName
+moduleName =
+  validateType $
+    Cabal.simpleParse <$> Dhall.string
+
+
+
+dhallToCabal :: FilePath -> LazyText.Text -> IO Cabal.GenericPackageDescription
+dhallToCabal fileName source =
+  input fileName source genericPackageDescription
+
+
+input :: FilePath -> LazyText.Text -> Dhall.Type a -> IO a
+input fileName source t = do
+  let
+    delta =
+      Directed ( StrictText.encodeUtf8 ( StrictText.pack fileName ) ) 0 0 0 0
+
+  expr  <-
+    throws ( Dhall.Parser.exprFromText delta source )
+
+  expr' <-
+    Dhall.Import.load expr
+
+  let
+    suffix =
+      Dhall.expected t
+        & build
+        & Builder.toLazyText
+        & LazyText.encodeUtf8
+        & LazyByteString.toStrict
+
+  let
+    annot =
+      case expr' of
+        Expr.Note ( Dhall.Parser.Src begin end bytes ) _ ->
+          Expr.Note
+            ( Dhall.Parser.Src begin end bytes' )
+            ( Expr.Annot expr' ( Dhall.expected t ) )
+
+          where
+
+          bytes' =
+            bytes <> " : " <> suffix
+
+        _ ->
+          Expr.Annot expr' ( Dhall.expected t )
+
+  _ <-
+    throws (Dhall.TypeCheck.typeOf annot)
+
+  case Dhall.extract t ( Dhall.Core.normalize expr' ) of
+    Just x  ->
+      return x
+
+    Nothing ->
+      throwIO Dhall.InvalidType
+
+  where
+
+    throws :: Exception e => Either e a -> IO a
+    throws =
+      either throwIO return
+
+
+
+pattern LamArr :: Expr.Expr s a -> Expr.Expr s a -> Expr.Expr s a
+pattern LamArr a b <- Expr.Lam _ a b
+
+
+
+pattern V0 v = Expr.Var ( Expr.V v 0 )
+
+
+
+versionRange :: Dhall.Type Cabal.VersionRange
+versionRange =
+  let
+    extract =
+      \case
+        LamArr _VersionRange (LamArr _anyVersion (LamArr _noVersion (LamArr _thisVersion (LamArr _notThisVersion (LamArr _laterVersion (LamArr _earlierVersion (LamArr _orLaterVersion (LamArr _orEarlierVersion (LamArr _withinVersion (LamArr _majorBoundVersion (LamArr _unionVersionRanges (LamArr _intersectVersionRanges (LamArr _differenceVersionRanges (LamArr _invertVersionRange versionRange)))))))))))))) ->
+          go versionRange
+
+        _ ->
+          Nothing
+
+    go =
+      \case
+        V0 "anyVersion" ->
+          return Cabal.anyVersion
+
+        V0 "noVersion" ->
+          return Cabal.noVersion
+
+        Expr.App ( V0 "thisVersion" ) components ->
+          Cabal.thisVersion <$> Dhall.extract version components
+
+        Expr.App ( V0 "notThisVersion" ) components ->
+          Cabal.notThisVersion <$> Dhall.extract version components
+
+        Expr.App ( V0 "laterVersion" ) components ->
+          Cabal.laterVersion <$> Dhall.extract version components
+
+        Expr.App ( V0 "earlierVersion" ) components ->
+          Cabal.earlierVersion <$> Dhall.extract version components
+
+        Expr.App ( V0 "orLaterVersion" ) components ->
+          Cabal.orLaterVersion <$> Dhall.extract version components
+
+        Expr.App ( V0 "orEarlierVersion" ) components ->
+          Cabal.orEarlierVersion <$> Dhall.extract version components
+
+        Expr.App ( Expr.App ( V0 "unionVersionRanges" ) a ) b ->
+          Cabal.unionVersionRanges <$> go a <*> go b
+
+        Expr.App ( Expr.App ( V0 "intersectVersionRanges" ) a ) b ->
+          Cabal.intersectVersionRanges <$> go a <*> go b
+
+        Expr.App ( Expr.App ( V0 "differenceVersionRanges" ) a ) b ->
+          Cabal.differenceVersionRanges <$> go a <*> go b
+
+        Expr.App ( V0 "invertVersionRange" ) components ->
+          Cabal.invertVersionRange <$> go components
+
+        Expr.App ( V0 "withinVersion" ) components ->
+          Cabal.withinVersion <$> Dhall.extract version components
+
+        Expr.App ( V0 "majorBoundVersion" ) components ->
+          Cabal.majorBoundVersion <$> Dhall.extract version components
+
+        _ ->
+          Nothing
+
+    expected =
+      let
+        versionRange =
+          V0 "VersionRange"
+
+        versionToVersionRange =
+          Expr.Pi
+            "_"
+            ( Dhall.expected version )
+            versionRange
+
+        combine =
+          Expr.Pi "_" versionRange ( Expr.Pi "_" versionRange versionRange )
+
+      in
+      Expr.Pi "VersionRange" ( Expr.Const Expr.Type )
+        $ Expr.Pi "anyVersion" versionRange
+        $ Expr.Pi "noVersion" versionRange
+        $ Expr.Pi "thisVersion" versionToVersionRange
+        $ Expr.Pi "notThisVersion" versionToVersionRange
+        $ Expr.Pi "laterVersion" versionToVersionRange
+        $ Expr.Pi "earlierVersion" versionToVersionRange
+        $ Expr.Pi "orLaterVersion" versionToVersionRange
+        $ Expr.Pi "orEarlierVersion" versionToVersionRange
+        $ Expr.Pi "withinVersion" versionToVersionRange
+        $ Expr.Pi "majorBoundVersion" versionToVersionRange
+        $ Expr.Pi "unionVersionRanges" combine
+        $ Expr.Pi "intersectVersionRanges" combine
+        $ Expr.Pi "differenceVersionRanges" combine
+        $ Expr.Pi
+            "invertVersionRange"
+            ( Expr.Pi "_" versionRange versionRange )
+            versionRange
+
+  in Dhall.Type { .. }
+
+
+
+buildType :: Dhall.Type Cabal.BuildType
+buildType =
+  sortType Dhall.genericAuto
+
+
+
+license :: Dhall.Type Cabal.License
+license =
+  makeUnion
+    ( Map.fromList
+        [ ( "GPL", Cabal.GPL <$> Dhall.maybe version )
+        , ( "AGPL", Cabal.AGPL <$> Dhall.maybe version )
+        , ( "LGPL", Cabal.LGPL <$> Dhall.maybe version )
+        , ( "BSD2", Cabal.BSD2 <$ Dhall.unit )
+        , ( "BSD3", Cabal.BSD3 <$ Dhall.unit )
+        , ( "BSD4", Cabal.BSD4 <$ Dhall.unit )
+        , ( "MIT", Cabal.MIT <$ Dhall.unit )
+        , ( "ISC", Cabal.ISC <$ Dhall.unit )
+        , ( "MPL", Cabal.MPL <$> version )
+        , ( "Apache", Cabal.Apache <$> Dhall.maybe version )
+        , ( "PublicDomain", Cabal.PublicDomain <$ Dhall.unit )
+        , ( "AllRightsReserved", Cabal.AllRightsReserved<$ Dhall.unit )
+        , ( "Unspecified", Cabal.UnspecifiedLicense <$ Dhall.unit )
+        , ( "Other", Cabal.OtherLicense <$ Dhall.unit )
+        ]
+    )
+
+
+
+compiler :: Dhall.Type ( Cabal.CompilerFlavor, Cabal.VersionRange )
+compiler =
+  makeRecord $
+    (,)
+      <$> keyValue "compiler" compilerFlavor
+      <*> keyValue "version" versionRange
+
+
+
+compilerFlavor :: Dhall.Type Cabal.CompilerFlavor
+compilerFlavor =
+  sortType Dhall.genericAuto
+
+
+
+repoType :: Dhall.Type Cabal.RepoType
+repoType =
+  sortType Dhall.genericAuto
+
+
+
+legacyExeDependency :: Dhall.Type Cabal.LegacyExeDependency
+legacyExeDependency =
+  makeRecord $ do
+    exe <-
+      keyValue "exe" Dhall.string
+
+    version <-
+      keyValue "version" versionRange
+
+    pure ( Cabal.LegacyExeDependency exe version )
+
+
+
+compilerOptions :: Dhall.Type [ ( Cabal.CompilerFlavor, [ String ] ) ]
+compilerOptions =
+  makeRecord $
+    sequenceA
+      [ (,) <$> pure Cabal.GHC <*> keyValue "GHC" options
+      , (,) <$> pure Cabal.GHCJS <*> keyValue "GHCJS" options
+      , (,) <$> pure Cabal.NHC <*> keyValue "NHC" options
+      , (,) <$> pure Cabal.YHC <*> keyValue "YHC" options
+      , (,) <$> pure Cabal.Hugs <*> keyValue "Hugs" options
+      , (,) <$> pure Cabal.HBC <*> keyValue "HBC" options
+      , (,) <$> pure Cabal.Helium <*> keyValue "Helium" options
+      , (,) <$> pure Cabal.JHC <*> keyValue "JHC" options
+      , (,) <$> pure Cabal.LHC <*> keyValue "LHC" options
+      , (,) <$> pure Cabal.UHC <*> keyValue "UHC" options
+      ]
+
+  where
+
+    options =
+      Dhall.list Dhall.string
+
+
+
+exeDependency :: Dhall.Type Cabal.ExeDependency
+exeDependency =
+  makeRecord $ do
+    packageName <-
+      keyValue "package" packageName
+
+    component <-
+      keyValue "component" unqualComponentName
+
+    version <-
+      keyValue "version" versionRange
+
+    pure ( Cabal.ExeDependency packageName component version )
+
+
+
+language :: Dhall.Type Cabal.Language
+language =
+  sortType Dhall.genericAuto
+
+
+
+pkgconfigDependency :: Dhall.Type Cabal.PkgconfigDependency
+pkgconfigDependency =
+  makeRecord $ do
+    name <-
+      keyValue "name" pkgconfigName
+
+    version <-
+      keyValue "version" versionRange
+
+    return ( Cabal.PkgconfigDependency name version )
+
+
+
+pkgconfigName :: Dhall.Type Cabal.PkgconfigName
+pkgconfigName =
+  Cabal.mkPkgconfigName <$> Dhall.string
+
+
+
+executableScope :: Dhall.Type Cabal.ExecutableScope
+executableScope =
+  makeUnion
+    ( Map.fromList
+        [ ( "Public", Cabal.ExecutablePublic <$ Dhall.unit )
+        , ( "Private", Cabal.ExecutablePrivate <$ Dhall.unit )
+        ]
+    )
+
+
+
+moduleReexport :: Dhall.Type Cabal.ModuleReexport
+moduleReexport =
+  makeRecord $ do
+    original <-
+      keyValue "original" $
+      makeRecord $ do
+        package <-
+          keyValue "package" ( Dhall.maybe packageName )
+
+        name <-
+          keyValue "name" moduleName
+
+        pure ( package, name )
+
+    moduleReexportName <-
+      keyValue "name" moduleName
+
+    pure
+      Cabal.ModuleReexport
+        { moduleReexportOriginalPackage = fst original
+        , moduleReexportOriginalName = snd original
+        , ..
+        }
+
+
+foreignLibOption :: Dhall.Type Cabal.ForeignLibOption
+foreignLibOption =
+  makeUnion
+    ( Map.fromList
+        [ ( "Standalone", Cabal.ForeignLibStandalone <$ Dhall.unit ) ]
+    )
+
+
+versionInfo :: Dhall.Type Cabal.LibVersionInfo
+versionInfo =
+  makeRecord $
+  fmap Cabal.mkLibVersionInfo $
+    (,,)
+      <$> ( fromIntegral <$> keyValue "current" Dhall.natural )
+      <*> ( fromIntegral <$> keyValue "revision" Dhall.natural )
+      <*> ( fromIntegral <$> keyValue "age" Dhall.natural )
+
+
+
+extension :: Dhall.Type Cabal.Extension
+extension =
+  let
+    knownExtension =
+      sortType Dhall.genericAuto
+
+    unitType =
+      Expr.Record Map.empty
+
+    extract expr = do
+      Expr.UnionLit k v alts <-
+        return expr
+
+      ext <-
+        Dhall.extract
+          knownExtension
+          ( Expr.UnionLit k ( Expr.RecordLit mempty ) ( unitType <$ alts ) )
+
+      case v of
+        Expr.BoolLit True ->
+          return ( Cabal.EnableExtension ext )
+
+        Expr.BoolLit False ->
+          return ( Cabal.DisableExtension ext )
+
+        _ ->
+          Nothing
+
+    expected =
+      case Dhall.expected knownExtension of
+        Expr.Union alts ->
+          sortExpr ( Expr.Union ( Expr.Bool <$ alts ) )
+
+        _ ->
+          error "Could not derive extension type"
+
+  in Dhall.Type { .. }
+
+
+
+guarded
+  :: ( Monoid a, Eq a, Diffable a )
+  => Dhall.Type a
+  -> Dhall.Type ( Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] a )
+guarded t =
+  let
+    extractConfVar body =
+      case body of
+        Expr.App ( Expr.App ( Expr.Field ( V0 "config" ) "impl" ) compiler ) version ->
+          Cabal.Impl
+            <$> Dhall.extract compilerFlavor compiler
+            <*> Dhall.extract versionRange version
+
+        Expr.App ( Expr.Field ( V0 "config" ) field ) x ->
+          case field of
+            "os" ->
+              Cabal.OS <$> Dhall.extract operatingSystem x
+
+            "arch" ->
+              Cabal.Arch <$> Dhall.extract arch x
+
+            "flag" ->
+              Cabal.Flag <$> Dhall.extract flagName x
+
+            _ ->
+              error "Unknown field"
+
+        _ ->
+          error ( "Unexpected guard expression. This is a bug, please report this! I'm stuck on: " ++ show body )
+
+    extract expr =
+      configTreeToCondTree [] <$> extractConfigTree ( toConfigTree expr )
+
+    extractConfigTree ( Leaf a ) =
+      Leaf <$> Dhall.extract t a
+
+    extractConfigTree ( Branch cond a b ) =
+      Branch <$> extractConfVar cond <*> extractConfigTree a <*> extractConfigTree b
+
+    configTreeToCondTree confVars = \case
+      Leaf a ->
+        Cabal.CondNode a mempty mempty
+
+      -- The condition has already been shown to hold. Consider only the true
+      -- branch and discard the false branch.
+      Branch confVar a _impossible | confVar `elem` confVars ->
+        configTreeToCondTree confVars a
+
+      Branch confVar a b ->
+        let
+          confVars' =
+            pure confVar <> confVars
+
+          true =
+            configTreeToCondTree confVars' a
+
+          false =
+            configTreeToCondTree confVars' b
+
+          ( common, true', false' ) =
+            diff ( Cabal.condTreeData true ) ( Cabal.condTreeData false )
+
+          ( duplicates, true'', false'' ) =
+            diff
+              ( Cabal.condTreeComponents false )
+              ( Cabal.condTreeComponents true )
+
+        in
+          Cabal.CondNode
+            common
+            mempty
+            ( mergeCommonGuards
+                ( Cabal.CondBranch
+                    ( Cabal.Var confVar )
+                    true
+                      { Cabal.condTreeData = true'
+                      , Cabal.condTreeComponents = true''
+                      }
+                    ( Just
+                        false
+                          { Cabal.condTreeData = false'
+                          , Cabal.condTreeComponents = false''
+                          }
+                    )
+                : duplicates
+                )
+            )
+
+    expected =
+        Expr.Pi "_" configRecordType ( Dhall.expected t )
+
+  in Dhall.Type { .. }
+
+
+
+catCondTree
+  :: ( Monoid c, Monoid a )
+  => Cabal.CondTree v c a -> Cabal.CondTree v c a -> Cabal.CondTree v c a
+catCondTree a b =
+  Cabal.CondNode
+    { Cabal.condTreeData =
+        Cabal.condTreeData a <> Cabal.condTreeData b
+    , Cabal.condTreeConstraints =
+        Cabal.condTreeConstraints a <> Cabal.condTreeConstraints b
+    , Cabal.condTreeComponents =
+        Cabal.condTreeComponents a <> Cabal.condTreeComponents b
+    }
+
+
+
+emptyCondTree :: ( Monoid b, Monoid c ) => Cabal.CondTree a b c
+emptyCondTree =
+  Cabal.CondNode mempty mempty mempty
+
+
+
+mergeCommonGuards
+  :: ( Monoid a, Monoid c, Eq v )
+  => [Cabal.CondBranch v c a]
+  -> [Cabal.CondBranch v c a]
+mergeCommonGuards [] =
+  []
+
+mergeCommonGuards ( a : as ) =
+  let
+    ( sameGuard, differentGuard ) =
+      partition
+        ( ( Cabal.condBranchCondition a == ) . Cabal.condBranchCondition )
+        as
+
+  in
+    a
+      { Cabal.condBranchIfTrue =
+          catCondTree
+            ( Cabal.condBranchIfTrue a )
+            ( foldl
+                catCondTree
+                emptyCondTree
+                ( Cabal.condBranchIfTrue <$> sameGuard )
+            )
+      , Cabal.condBranchIfFalse =
+          Just
+            ( catCondTree
+              ( fromMaybe emptyCondTree ( Cabal.condBranchIfFalse a ) )
+              ( foldl
+                  catCondTree
+                  emptyCondTree
+                  ( fromMaybe emptyCondTree
+                      . Cabal.condBranchIfFalse
+                      <$> sameGuard
+                  )
+              )
+            )
+      }
+      : mergeCommonGuards differentGuard
+
+
+
+configRecordType :: Expr.Expr Dhall.Parser.Src Dhall.TypeCheck.X
+configRecordType =
+  let
+    predicate on =
+      Expr.Pi "_" on Expr.Bool
+
+  in
+    Expr.Record
+      ( Map.fromList
+          [ ( "os", predicate ( Dhall.expected operatingSystem ) )
+          , ( "arch", predicate ( Dhall.expected arch ) )
+          , ( "flag", predicate ( Dhall.expected flagName ) )
+          , ( "impl"
+            , Expr.Pi
+                "_"
+                ( Dhall.expected compilerFlavor )
+                ( Expr.Pi "_" ( Dhall.expected versionRange ) Expr.Bool )
+            )
+          ]
+      )
+
+
+
+genericPackageDescription :: Dhall.Type Cabal.GenericPackageDescription
+genericPackageDescription =
+  let
+    namedList k t =
+      Dhall.list
+        ( makeRecord
+            ( (,)
+                <$> keyValue "name" unqualComponentName
+                <*> keyValue k ( guarded t )
+            )
+        )
+
+  in
+    makeRecord $ do
+      packageDescription <-
+        packageDescription
+
+      genPackageFlags <-
+        keyValue "flags" ( Dhall.list flag )
+
+      condLibrary <-
+        keyValue "library" ( Dhall.maybe ( guarded library ) )
+
+      condSubLibraries <-
+        keyValue "sub-libraries" ( namedList "library" library )
+
+      condForeignLibs <-
+        keyValue "foreign-libraries" ( namedList "foreign-lib" foreignLib )
+
+      condExecutables <-
+        keyValue "executables" ( namedList "executable" executable )
+
+      condTestSuites <-
+        keyValue "test-suites" ( namedList "test-suite" testSuite )
+
+      condBenchmarks <-
+        keyValue "benchmarks" ( namedList "benchmark" benchmark )
+
+      return Cabal.GenericPackageDescription { .. }
+
+
+
+operatingSystem :: Dhall.Type Cabal.OS
+operatingSystem =
+  sortType Dhall.genericAuto
+
+
+
+arch :: Dhall.Type Cabal.Arch
+arch =
+  sortType Dhall.genericAuto
+
+
+
+flag :: Dhall.Type Cabal.Flag
+flag =
+  makeRecord $ do
+    flagName <-
+      keyValue "name" flagName
+
+    flagDefault <-
+      keyValue "default" Dhall.bool
+
+    flagDescription <-
+      keyValue "description" Dhall.string
+
+    flagManual <-
+      keyValue "manual" Dhall.bool
+
+    return Cabal.MkFlag { .. }
+
+
+
+flagName :: Dhall.Type Cabal.FlagName
+flagName =
+  Cabal.mkFlagName <$> Dhall.string
+
+
+
+setupBuildInfo :: Dhall.Type Cabal.SetupBuildInfo
+setupBuildInfo =
+  makeRecord $ do
+    setupDepends <-
+      keyValue "setup-depends" ( Dhall.list dependency )
+
+    defaultSetupDepends <-
+      pure False
+
+    return Cabal.SetupBuildInfo { .. }
+
+
+
+filePath :: Dhall.Type FilePath
+filePath =
+  Dhall.string
+
+
+
+mixin :: Dhall.Type Cabal.Mixin
+mixin =
+  makeRecord $ do
+    mixinPackageName <-
+      keyValue "package" packageName
+
+    mixinIncludeRenaming <-
+      keyValue "renaming" includeRenaming
+
+    pure Cabal.Mixin { .. }
+
+
+
+includeRenaming :: Dhall.Type Cabal.IncludeRenaming
+includeRenaming =
+  makeRecord $ do
+    includeProvidesRn <-
+      keyValue "provides" moduleRenaming
+
+    includeRequiresRn <-
+      keyValue "requires" moduleRenaming
+
+    pure Cabal.IncludeRenaming { .. }
+
+
+
+moduleRenaming :: Dhall.Type Cabal.ModuleRenaming
+moduleRenaming =
+  fmap Cabal.ModuleRenaming $
+  Dhall.list $
+  makeRecord $
+    (,) <$> keyValue "rename" moduleName <*> keyValue "to" moduleName
+
+
+sortType :: Dhall.Type a -> Dhall.Type a
+sortType t =
+  t { Dhall.expected = sortExpr ( Dhall.expected t ) }
diff --git a/lib/DhallToCabal/ConfigTree.hs b/lib/DhallToCabal/ConfigTree.hs
new file mode 100644
--- /dev/null
+++ b/lib/DhallToCabal/ConfigTree.hs
@@ -0,0 +1,186 @@
+{-# language DeriveFunctor #-}
+{-# language LambdaCase #-}
+{-# language OverloadedStrings #-}
+
+module DhallToCabal.ConfigTree ( ConfigTree(..), toConfigTree ) where
+
+import Control.Monad
+import Dhall.Core hiding ( Const )
+
+
+-- | 'ConfigTree' captures a logic-monad like expansion of the result of
+-- Bool-valued expressions.
+
+data ConfigTree cond a
+  = Leaf a
+  | Branch cond ( ConfigTree cond a ) ( ConfigTree cond a )
+  deriving (Functor, Show)
+
+instance Applicative ( ConfigTree cond ) where
+  pure = return
+  (<*>) = ap
+
+instance Monad ( ConfigTree cond ) where
+  return = Leaf
+
+  Leaf a >>= f = f a
+  Branch cond l r >>= f = Branch cond ( l >>= f ) ( r >>= f )
+
+
+
+-- | Given a Dhall expression that is of the form @λ( config : Config ) -> a@,
+-- find all saturated uses of @config@, and substitute in either @True@ or
+-- @False@. The two substitutions are captured in a 'Branch'.
+
+toConfigTree
+  :: ( Eq a, Eq s )
+  => Expr s a
+  -> ConfigTree ( Expr s a ) ( Expr s a )
+toConfigTree e =
+  let
+    v =
+      "config"
+
+    saturated =
+      normalize ( App e ( Var v ) )
+
+    loop e =
+      case normalize <$> rewriteConfigUse v e of
+        Leaf a ->
+          Leaf a
+
+        Branch cond l r ->
+          Branch cond ( loop =<< l ) ( loop =<< r )
+
+  in loop saturated
+
+
+
+-- | Find all config-like uses of a given variable, and expand them into all
+-- possible results of evaluation.
+
+rewriteConfigUse :: Var -> Expr s a -> ConfigTree (Expr s a) (Expr s a)
+rewriteConfigUse v =
+ transformMOf
+   subExpr
+   ( \expr ->
+       if isConfigUse expr then
+         Branch
+           expr
+             ( pure ( BoolLit True ) )
+             ( pure ( BoolLit False ) )
+       else
+         pure expr
+   )
+
+  where
+    
+    isConfigUse (App (Field (Var x') "os") _)           | v == x' = True
+    isConfigUse (App (Field (Var x') "arch") _)         | v == x' = True
+    isConfigUse (App (App (Field (Var x') "impl") _) _) | v == x' = True
+    isConfigUse (App (Field (Var x') "flag") _)         | v == x' = True
+    isConfigUse _ = False
+
+
+-- | Transform every element in a tree using a user supplied 'Traversal' in a
+-- bottom-up manner with a monadic effect.
+transformMOf
+  :: Monad m =>
+  ( ( t -> m b ) -> t -> m a ) -> ( a -> m b ) -> t -> m b
+transformMOf l f = go where
+  go t = l go t >>= f
+{-# INLINE transformMOf #-}
+
+
+
+subExpr
+  :: Applicative f
+  => ( Expr s a -> f ( Expr s a ) ) -> Expr s a -> f ( Expr s a )
+subExpr f = \case
+  Lam a b c ->
+    Lam a <$> f b <*> f c
+
+  Pi a b c ->
+    Pi a <$> f b <*> f c
+
+  App a b ->
+    App <$> f a <*> f b
+
+  Let a b c d ->
+    Let a <$> traverse f b <*> f c <*> f d
+
+  Annot a b ->
+    Annot <$> f a <*> f b
+
+  BoolAnd a b ->
+    BoolAnd <$> f a <*> f b
+
+  BoolOr a b ->
+    BoolOr <$> f a <*> f b
+
+  BoolEQ a b ->
+    BoolEQ <$> f a <*> f b
+
+  BoolNE a b ->
+    BoolNE <$> f a <*> f b
+
+  BoolIf a b c ->
+    BoolIf <$> f a <*> f b <*> f c
+
+  NaturalPlus a b ->
+    NaturalPlus <$> f a <*> f b
+
+  NaturalTimes a b ->
+    NaturalTimes <$> f a <*> f b
+
+  TextLit (Chunks a b) ->
+    TextLit
+      <$>
+        ( Chunks
+            <$> traverse ( \(a,b) -> (,) <$> pure a <*> f b ) a <*> pure b
+        )
+
+  TextAppend a b ->
+    TextAppend <$> f a <*> f b
+
+  ListLit a b ->
+    ListLit <$> traverse f a <*> traverse f b
+
+  ListAppend a b ->
+    ListAppend <$> f a <*> f b
+
+  OptionalLit a b ->
+    OptionalLit <$> f a <*> traverse f b
+
+  Record a ->
+    Record <$> traverse f a
+
+  RecordLit a ->
+    RecordLit <$> traverse f a
+
+  Union a ->
+    Union <$> traverse f a
+
+  UnionLit a b c ->
+    UnionLit a <$> f b <*> traverse f c
+
+  Combine a b ->
+    Combine <$> f a <*> f b
+
+  Prefer a b ->
+    Prefer <$> f a <*> f b
+
+  Merge a b t ->
+    Merge <$> f a <*> f b <*> traverse f t
+
+  Constructors a ->
+    Constructors <$> f a
+
+  Field a b ->
+    Field <$> f a <*> pure b
+
+  Note a b ->
+    Note a <$> f b
+
+  e ->
+    pure e
diff --git a/lib/DhallToCabal/Diff.hs b/lib/DhallToCabal/Diff.hs
new file mode 100644
--- /dev/null
+++ b/lib/DhallToCabal/Diff.hs
@@ -0,0 +1,217 @@
+{-# language DefaultSignatures #-}
+{-# language FlexibleContexts #-}
+{-# language TypeOperators #-}
+
+module DhallToCabal.Diff ( Diffable(..) ) where
+
+import Data.List ( (\\), intersect )
+
+import qualified Distribution.PackageDescription as Cabal
+import qualified Distribution.Types.ExecutableScope as Cabal
+import qualified Distribution.Types.ForeignLib as Cabal
+import qualified Distribution.Types.ForeignLibType as Cabal
+import qualified Distribution.Types.UnqualComponentName as Cabal
+import qualified GHC.Generics as Generic
+
+
+
+diffEqVia :: ( Monoid a, Eq b ) => ( a -> b ) -> a -> a -> ( b, b, b )
+diffEqVia f left right =
+  if f left == f right then
+    ( f left, f mempty, f mempty )
+  else
+    ( f mempty, f left, f right )
+
+
+
+class Diffable a where
+  diff :: a -> a -> ( a, a, a )
+  default diff :: ( Generic.Generic a, GDiffable ( Generic.Rep a ) ) => a -> a -> ( a, a, a )
+  diff a b =
+    let
+      ( common, left, right ) =
+        gdiff ( Generic.from a ) ( Generic.from b )
+
+    in
+      ( Generic.to common, Generic.to left, Generic.to right )
+
+
+
+instance Diffable Cabal.BuildInfo where
+  diff a b =
+    let
+      ( commonBuildable, leftBuildable, rightBuildable ) =
+        diffEqVia Cabal.buildable a b
+
+      ( common, left, right ) =
+        case gdiff ( Generic.from a ) ( Generic.from b ) of
+          ( common, left, right ) ->
+            ( Generic.to common, Generic.to left, Generic.to right )
+
+    in
+      ( common { Cabal.buildable = commonBuildable }
+      , left { Cabal.buildable = leftBuildable }
+      , right { Cabal.buildable = rightBuildable }
+      )
+
+
+
+instance Diffable Cabal.Library where
+  diff a b =
+    let
+      ( commonLibExposed, leftLibExposed, rightLibExposed ) =
+        diffEqVia Cabal.libExposed a b
+
+      ( common, left, right ) =
+        case gdiff ( Generic.from a ) ( Generic.from b ) of
+          ( common, left, right ) ->
+            ( Generic.to common, Generic.to left, Generic.to right )
+
+    in
+      ( common { Cabal.libExposed = commonLibExposed }
+      , left { Cabal.libExposed = leftLibExposed }
+      , right { Cabal.libExposed = rightLibExposed }
+      )
+
+
+instance Diffable Cabal.Benchmark
+
+
+
+instance Diffable Cabal.TestSuite
+
+
+
+instance Diffable Cabal.Executable where
+  diff a b =
+    let
+      ( commonModulePath, leftModulePath, rightModulePath ) =
+        diffEqVia Cabal.modulePath a b
+
+      ( common, left, right ) =
+        case gdiff ( Generic.from a ) ( Generic.from b ) of
+          ( common, left, right ) ->
+            ( Generic.to common, Generic.to left, Generic.to right )
+
+    in
+      ( common { Cabal.modulePath = commonModulePath }
+      , left { Cabal.modulePath = leftModulePath }
+      , right { Cabal.modulePath = rightModulePath }
+      )
+
+
+
+instance Diffable Cabal.ForeignLib
+
+
+
+instance Eq a => Diffable ( Maybe a ) where
+  diff left right =
+    if left == right then
+      ( left, Nothing, Nothing )
+    else
+      ( Nothing, left, right )
+
+
+
+instance Diffable Cabal.UnqualComponentName where
+  diff left right =
+    if left == right then
+      ( left, mempty, mempty )
+    else
+      ( mempty, left, right )
+
+
+
+instance Diffable Cabal.BenchmarkInterface where
+  diff left right =
+    if left == right then
+      ( left, mempty, mempty )
+    else
+      ( mempty, left, right )
+
+
+
+instance Diffable Cabal.ForeignLibType where
+  diff left right =
+    if left == right then
+      ( left, mempty, mempty )
+    else
+      ( mempty, left, right )
+
+
+
+instance Diffable Cabal.TestSuiteInterface where
+  diff left right =
+    if left == right then
+      ( left, mempty, mempty )
+    else
+      ( mempty, left, right )
+
+
+
+instance Diffable Cabal.ExecutableScope where
+  diff left right =
+    if left == right then
+      ( left, mempty, mempty )
+    else
+      ( mempty, left, right )
+
+
+
+instance Eq a => Diffable [a] where
+  diff a b =
+    ( intersect a b
+    , a \\ b
+    , b \\ a
+    )
+
+
+
+instance Diffable Bool where
+  diff left right =
+    if left == right then
+      ( left, True, True )
+    else
+      ( True, left, right )
+
+
+
+class GDiffable f where
+  gdiff :: f a -> f a -> ( f a, f a, f a )
+
+
+
+instance GDiffable f => GDiffable ( Generic.M1 i c f ) where
+  gdiff ( Generic.M1 a ) ( Generic.M1 b ) =
+    let
+      ( common, left, right ) =
+        gdiff a b
+
+    in
+      ( Generic.M1 common, Generic.M1 left, Generic.M1 right )
+
+
+
+instance ( GDiffable f, GDiffable g ) => GDiffable ( f Generic.:*: g ) where
+  gdiff ( a Generic.:*: x ) ( b Generic.:*: y ) =
+    let
+      ( common0, left0, right0 ) =
+        gdiff a b
+
+      ( common1, left1, right1 ) =
+        gdiff x y
+
+    in
+      ( common0 Generic.:*: common1, left0 Generic.:*: left1, right0 Generic.:*: right1 )
+
+
+
+instance Diffable a => GDiffable ( Generic.K1 i a ) where
+  gdiff ( Generic.K1 a ) ( Generic.K1 b ) =
+    let
+      ( common, left, right ) =
+        diff a b
+
+    in
+      ( Generic.K1 common, Generic.K1 left, Generic.K1 right )
