diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,101 @@
+1.26.0
+
+* [Supports version 10.0.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v10.0.0)
+* BREAKING CHANGE TO THE LANGUAGE: [Remove old union literal syntax](https://github.com/dhall-lang/dhall-haskell/pull/1176)
+    * Union literals of the form `< x = e | ... >` are no longer valid
+    * For more details, see: [Migration: Deprecation of old union literal syntax](https://github.com/dhall-lang/dhall-lang/wiki/Migration%3A-Deprecation-of-old-union-literal-syntax)
+    * Also see the [changelog for standard version 10.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v10.0.0) for more details
+* BREAKING CHANGE TO THE API: [Change `X` to be a type synonym for `Data.Void`](https://github.com/dhall-lang/dhall-haskell/pull/1172)
+    * This is a breaking change if you were previously pattern matching on the
+      `X` constructor.  You can replace that with the use of `Data.Void.absurd`
+* BREAKING CHANGE TO THE API: [Treat multi-`let`s as syntactic sugar](https://github.com/dhall-lang/dhall-haskell/pull/1242)
+    * This is a breaking change because the `Let` constructor now only stores
+      one `Binding` instead of a `NonEmpty` list of `Binding`s
+* PERFORMANCE REGRESSION & TECHNICALLY BREAKING CHANGE TO THE LANGUAGE: [Dependent types](https://github.com/dhall-lang/dhall-haskell/pull/1164)
+    * You can now write functions from terms to types
+    * There is also now language support for tests of the form
+      `assert : x === y`
+    * This deteriorates the performance of large multi-`let` expressions
+      (See: [#1306](https://github.com/dhall-lang/dhall-haskell/issues/1306))
+    * Splitting large multi-`let` expressions into smaller files may mitigate
+      the problem as a work-around for now
+    * Follow [#1129](https://github.com/dhall-lang/dhall-haskell/issues/1129)
+      for work to fix this performance regression
+    * This is also a technically breaking change because `assert` is now a
+      reserved keyword
+    * See the [changelog for standard version 10.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v10.0.0) for more details
+* TECHNICALLY BREAKING CHANGE TO THE LANGUAGE: [Add `Natural/subtract` built-in](https://github.com/dhall-lang/dhall-haskell/pull/1133)
+    * The language now supports machine subtraction, which can be used to
+      support several other high-performance operations (like `Natural`
+      comparisons)
+    * This is a technically breaking change if you used `Natural/subtract` as an
+      identifier in your code
+    * See the [changelog for standard version 10.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v10.0.0) for more details
+* TECHNICALLY BREAKING CHANGE TO THE LANGUAGE: [More simplifications for field selection](https://github.com/dhall-lang/dhall-haskell/pull/1174)
+    * Now the interpreter will more intelligently simplify certain field
+      projections
+    * For example: `λ(x : { a : Bool, b : Bool }) → (x ⫽ { c = 0 }).{ a, c }.c`
+      will now simplify to `λ(x : { a : Bool, b : Bool }) → 0 `
+    * This is a technically breaking change because you will need to update
+      integrity checks that protect code simplified in this way
+    * See the [changelog for standard version 10.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v10.0.0) for more details
+* TECHNICALLY BREAKING CHANGE TO THE LANGUAGE: [Simplify `⫽` when its arguments are equivalent](https://github.com/dhall-lang/dhall-haskell/pull/1196)
+    * This is a technically breaking change for the same reason: this will
+      perturb semantic integrity checks for affected code
+    * See the [changelog for standard version 10.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v10.0.0) for more details
+* NEW FEATURE: [Restore support for records containing both types and terms](https://github.com/dhall-lang/dhall-haskell/pull/1173)
+    * In other words `{ foo = 1, bar = Bool }` is now valid again
+    * This means that you now can export a single package containing both types
+      and terms
+    * See the [changelog for standard version 10.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v10.0.0) for more details
+* [`dhall format` now preserves `let` comments](https://github.com/dhall-lang/dhall-haskell/pull/1273)
+    * `dhall` format will now preserve comments in the following locations of
+      a `let` binding:
+    * `let {- HERE -} x {- HERE -} : {- HERE -} Bool = {- HERE -} True in x`
+    * This support handles both single-line and multi-line comments and also
+      takes care of correctly indenting/dedenting them
+    * Note that comments before the `let` keyword are still not preserved
+      (unless it is the beginning of the file)
+* [Add API support for marshalling recursive types](https://github.com/dhall-lang/dhall-haskell/pull/1195)
+    * You can now marshal recursive types from Dhall into Haskell using the
+      newly-added utilities
+    * See also: [#1298](https://github.com/dhall-lang/dhall-haskell/pull/1298)
+* [New `:help` command for `dhall repl`](https://github.com/dhall-lang/dhall-haskell/pull/1237)
+* [New `--no-cache` flag](https://github.com/dhall-lang/dhall-haskell/pull/1290)
+    * You can now disable use of the cache with this flag
+    * This comes in handy if you want to disable α-normalization for imports
+      protected by a semantic integrity check
+* Bug fixes
+    * [Fix `isNormalized` for field selections](https://github.com/dhall-lang/dhall-haskell/pull/1210)
+    * [Simplify `Natural/subtract` when its arguments are equivalent](https://github.com/dhall-lang/dhall-haskell/pull/1220)
+    * [Fix `NaN` to be judgmentally equivalent to itself](https://github.com/dhall-lang/dhall-haskell/pull/1231)
+    * [Fix `Inject` instance for lists](https://github.com/dhall-lang/dhall-haskell/pull/1261)
+    * [Fix typechecking of `toMap`](https://github.com/dhall-lang/dhall-haskell/pull/1279)
+* Performance optimizations
+    * [Optimize a few `Set` instances](https://github.com/dhall-lang/dhall-haskell/pull/1184)
+    * [Remove some redundant sorting during normalization](https://github.com/dhall-lang/dhall-haskell/pull/1228)
+* Improvements to error messages
+    * [Improve error reporting for failed remote imports](https://github.com/dhall-lang/dhall-haskell/pull/1188)
+    * [Improve HTTP errors](https://github.com/dhall-lang/dhall-haskell/pull/1253)
+* Improvements to formatting
+    * [Indent function arguments when formatting](https://github.com/dhall-lang/dhall-haskell/pull/1167)
+    * [Prefer unquoted URLs](https://github.com/dhall-lang/dhall-haskell/pull/1235)
+    * [Strip leading whitespace](https://github.com/dhall-lang/dhall-haskell/pull/1270)
+* Improvements to diffs
+    * [Fix diffs for lists](https://github.com/dhall-lang/dhall-haskell/pull/1213)
+    * [Improve diff for non-empty lists](https://github.com/dhall-lang/dhall-haskell/pull/1244)
+    * [Small fixes to `dhall diff`](https://github.com/dhall-lang/dhall-haskell/pull/1263)
+* Improvements to documentation
+    * [Fix documentation for `UnionInputType`](https://github.com/dhall-lang/dhall-haskell/pull/1230)
+    * [Document support for caching protected imports](https://github.com/dhall-lang/dhall-haskell/pull/1247)
+* Improvements to command-line interface
+    * [Improve description of `dhall lint`](https://github.com/dhall-lang/dhall-haskell/pull/1264)
+    * [Change `dhall type` to resolve imports](https://github.com/dhall-lang/dhall-haskell/pull/1281)
+
 1.25.0
 
-* Supports version 8.0.0 of the standard
-    * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v8.0.0
+* Supports version 9.0.0 of the standard
+    * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v9.0.0
 * BREAKING CHANGE: Remove support for old-style `List`-like `Optional` literals
     * List-like `Optional` Literals (i.e. `[ 1 ] : Optional Natural`) are no
       longer valid
diff --git a/benchmark/deep-nested-large-record/Main.hs b/benchmark/deep-nested-large-record/Main.hs
--- a/benchmark/deep-nested-large-record/Main.hs
+++ b/benchmark/deep-nested-large-record/Main.hs
@@ -25,7 +25,7 @@
 issue412 prelude = Gauge.whnf TypeCheck.typeOf expr
   where
     expr
-      = Core.Let (pure (Core.Binding "prelude" Nothing prelude))
+      = Core.Let (Core.Binding Nothing "prelude" Nothing Nothing Nothing prelude)
       $ Core.ListLit Nothing
       $ Seq.replicate 5
       $ Core.Var (Core.V "prelude" 0) `Core.Field` "types" `Core.Field` "Little" `Core.Field` "Foo"
@@ -33,15 +33,27 @@
 unionPerformance :: Core.Expr s TypeCheck.X -> Gauge.Benchmarkable
 unionPerformance prelude = Gauge.whnf TypeCheck.typeOf expr
   where
-    innerBinding =
-        Core.Binding "big" Nothing
-            (prelude `Core.Field` "types" `Core.Field` "Big")
-
-    outerBinding =
-        Core.Binding "x" Nothing
-            (Core.Let (pure innerBinding) (Core.Prefer "big" "big"))
-
-    expr = Core.Let (pure outerBinding) "x"
+    expr =
+        Core.Let
+            (Core.Binding
+                Nothing
+                "x"
+                Nothing
+                Nothing
+                Nothing
+                (Core.Let
+                    (Core.Binding
+                        Nothing
+                        "big"
+                        Nothing
+                        Nothing
+                        Nothing
+                        (prelude `Core.Field` "types" `Core.Field` "Big")
+                    )
+                    (Core.Prefer "big" "big")
+                )
+            )
+            "x"
 
 main :: IO ()
 main = do
diff --git a/benchmark/examples/issue108.dhall b/benchmark/examples/issue108.dhall
--- a/benchmark/examples/issue108.dhall
+++ b/benchmark/examples/issue108.dhall
@@ -1,61 +1,62 @@
-λ(xs : List { cores : Natural, host : Text, key : Text, mandatoryFeatures : 
-List Text, platforms : List < AArch64_Linux : {} | ARMv5tel_Linux : {} | 
-ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : {} | MIPS64el_Linux : {} | 
-PowerPC_Linux : {} | X86_64_Cygwin : {} | X86_64_Darwin : {} | X86_64_FreeBSD : 
-{} | X86_64_Linux : {} | X86_64_Solaris : {} >, speedFactor : Natural, 
-supportedFeatures : List Text, user : Optional Text }) → List/fold { cores : 
-Natural, host : Text, key : Text, mandatoryFeatures : List Text, platforms : 
-List < AArch64_Linux : {} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} | 
-I686_Cygwin : {} | I686_Linux : {} | MIPS64el_Linux : {} | PowerPC_Linux : {} | 
-X86_64_Cygwin : {} | X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux : 
-{} | X86_64_Solaris : {} >, speedFactor : Natural, supportedFeatures : List 
-Text, user : Optional Text } xs Text (λ(x : { cores : Natural, host : Text, 
-key : Text, mandatoryFeatures : List Text, platforms : List < AArch64_Linux : 
-{} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : 
-{} | MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} | 
-X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris : 
-{} >, speedFactor : Natural, supportedFeatures : List Text, user : Optional 
-Text }) → λ(y : Text) → (Optional/fold Text x.user Text (λ(user : Text) 
-→ user ++ "@" ++ x.host ++ "") x.host ++ " " ++ (merge { Empty = λ(_ : {}) 
-→ "", NonEmpty = λ(result : Text) → result } (List/fold < AArch64_Linux : 
-{} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : 
-{} | MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} | 
-X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris : 
-{} > x.platforms < Empty : {} | NonEmpty : Text > (λ(element : < AArch64_Linux 
-: {} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux 
-: {} | MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} | 
-X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris : 
-{} >) → λ(status : < Empty : {} | NonEmpty : Text >) → merge { Empty = 
-λ(_ : {}) → < NonEmpty = merge { AArch64_Linux = λ(_ : {}) → 
-"aarch64-linux", ARMv5tel_Linux = λ(_ : {}) → "armv5tel-linux", ARMv7l_Linux 
-= λ(_ : {}) → "armv7l-linux", I686_Cygwin = λ(_ : {}) → "i686-cygwin", 
-I686_Linux = λ(_ : {}) → "i686-linux", MIPS64el_Linux = λ(_ : {}) → 
-"mips64el-linux", PowerPC_Linux = λ(_ : {}) → "powerpc-linux", X86_64_Cygwin 
-= λ(_ : {}) → "x86_64-cygwin", X86_64_Darwin = λ(_ : {}) → 
-"x86_64-darwin", X86_64_FreeBSD = λ(_ : {}) → "x86_64-freebsd", X86_64_Linux 
-= λ(_ : {}) → "x86_64-linux", X86_64_Solaris = λ(_ : {}) → 
-"x86_64-solaris" } element | Empty : {} >, NonEmpty = λ(result : Text) → < 
-NonEmpty = (merge { AArch64_Linux = λ(_ : {}) → "aarch64-linux", 
-ARMv5tel_Linux = λ(_ : {}) → "armv5tel-linux", ARMv7l_Linux = λ(_ : {}) → 
-"armv7l-linux", I686_Cygwin = λ(_ : {}) → "i686-cygwin", I686_Linux = λ(_ : 
-{}) → "i686-linux", MIPS64el_Linux = λ(_ : {}) → "mips64el-linux", 
-PowerPC_Linux = λ(_ : {}) → "powerpc-linux", X86_64_Cygwin = λ(_ : {}) → 
-"x86_64-cygwin", X86_64_Darwin = λ(_ : {}) → "x86_64-darwin", X86_64_FreeBSD 
-= λ(_ : {}) → "x86_64-freebsd", X86_64_Linux = λ(_ : {}) → 
-"x86_64-linux", X86_64_Solaris = λ(_ : {}) → "x86_64-solaris" } element) ++ 
-"," ++ result | Empty : {} > } status : < Empty : {} | NonEmpty : Text >) < 
-Empty = {=} | NonEmpty : Text >) : Text) ++ " " ++ x.key ++ " " ++ Integer/show 
-(Natural/toInteger x.cores) ++ " " ++ Integer/show (Natural/toInteger 
-x.speedFactor) ++ " " ++ (merge { Empty = λ(_ : {}) → "", NonEmpty = 
-λ(result : Text) → result } (List/fold Text x.supportedFeatures < Empty : {} 
-| NonEmpty : Text > (λ(element : Text) → λ(status : < Empty : {} | NonEmpty 
-: Text >) → merge { Empty = λ(_ : {}) → < NonEmpty = element | Empty : {} 
->, NonEmpty = λ(result : Text) → < NonEmpty = element ++ "," ++ result | 
-Empty : {} > } status : < Empty : {} | NonEmpty : Text >) < Empty = {=} | 
-NonEmpty : Text >) : Text) ++ " " ++ (merge { Empty = λ(_ : {}) → "", 
-NonEmpty = λ(result : Text) → result } (List/fold Text x.mandatoryFeatures < 
-Empty : {} | NonEmpty : Text > (λ(element : Text) → λ(status : < Empty : {} 
-| NonEmpty : Text >) → merge { Empty = λ(_ : {}) → < NonEmpty = element | 
-Empty : {} >, NonEmpty = λ(result : Text) → < NonEmpty = element ++ "," ++ 
-result | Empty : {} > } status : < Empty : {} | NonEmpty : Text >) < Empty = 
-{=} | NonEmpty : Text >) : Text) ++ "\n") ++ y) ""
+λ ( xs : List { cores : Natural , host : Text , key : Text , mandatoryFeatures :
+List Text , platforms : List < AArch64_Linux : {} | ARMv5tel_Linux : {} |
+ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : {} | MIPS64el_Linux : {} |
+PowerPC_Linux : {} | X86_64_Cygwin : {} | X86_64_Darwin : {} | X86_64_FreeBSD :
+{} | X86_64_Linux : {} | X86_64_Solaris : {} > , speedFactor : Natural ,
+supportedFeatures : List Text , user : Optional Text } )→ List/fold { cores :
+Natural , host : Text , key : Text , mandatoryFeatures : List Text , platforms :
+List < AArch64_Linux : {} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} |
+I686_Cygwin : {} | I686_Linux : {} | MIPS64el_Linux : {} | PowerPC_Linux : {} |
+X86_64_Cygwin : {} | X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux :
+{} | X86_64_Solaris : {} > , speedFactor : Natural , supportedFeatures : List
+Text , user : Optional Text } xs Text ( λ ( x : { cores : Natural , host : Text
+, key : Text , mandatoryFeatures : List Text , platforms : List < AArch64_Linux
+: {} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux :
+{} | MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} |
+X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris :
+{} > , speedFactor : Natural , supportedFeatures : List Text , user : Optional
+Text } ) → λ(y : Text) → Optional/fold Text x.user Text (λ(user : Text) → user
+++ "@" ++ x.host ++ "") x.host ++ " " ++ ( merge { Empty = λ(_ : {}) → "",
+NonEmpty = λ(result : Text) → result } ( List/fold < AArch64_Linux : {} |
+ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : {} |
+MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} | X86_64_Darwin :
+{} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris : {} > x.platforms
+< Empty : {} | NonEmpty : Text > ( λ ( element : < AArch64_Linux : {} |
+ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : {} |
+MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} | X86_64_Darwin :
+{} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris : {} > ) →
+λ(status : < Empty : {} | NonEmpty : Text >) → merge { Empty = λ(_ : {}) → <
+NonEmpty : Text | Empty : {} >.NonEmpty ( merge { AArch64_Linux = λ(_ : {}) →
+"aarch64-linux" , ARMv5tel_Linux = λ(_ : {}) → "armv5tel-linux" , ARMv7l_Linux =
+λ(_ : {}) → "armv7l-linux" , I686_Cygwin = λ(_ : {}) → "i686-cygwin" ,
+I686_Linux = λ(_ : {}) → "i686-linux" , MIPS64el_Linux = λ(_ : {}) →
+"mips64el-linux" , PowerPC_Linux = λ(_ : {}) → "powerpc-linux" , X86_64_Cygwin =
+λ(_ : {}) → "x86_64-cygwin" , X86_64_Darwin = λ(_ : {}) → "x86_64-darwin" ,
+X86_64_FreeBSD = λ(_ : {}) → "x86_64-freebsd" , X86_64_Linux = λ(_ : {}) →
+"x86_64-linux" , X86_64_Solaris = λ(_ : {}) → "x86_64-solaris" } element ) ,
+NonEmpty = λ(result : Text) → < NonEmpty : Text | Empty : {} >.NonEmpty ( (
+merge { AArch64_Linux = λ(_ : {}) → "aarch64-linux" , ARMv5tel_Linux = λ(_ : {})
+→ "armv5tel-linux" , ARMv7l_Linux = λ(_ : {}) → "armv7l-linux" , I686_Cygwin =
+λ(_ : {}) → "i686-cygwin" , I686_Linux = λ(_ : {}) → "i686-linux" ,
+MIPS64el_Linux = λ(_ : {}) → "mips64el-linux" , PowerPC_Linux = λ(_ : {}) →
+"powerpc-linux" , X86_64_Cygwin = λ(_ : {}) → "x86_64-cygwin" , X86_64_Darwin =
+λ(_ : {}) → "x86_64-darwin" , X86_64_FreeBSD = λ(_ : {}) → "x86_64-freebsd" ,
+X86_64_Linux = λ(_ : {}) → "x86_64-linux" , X86_64_Solaris = λ(_ : {}) →
+"x86_64-solaris" } element ) ++ "," ++ result ) } status : < Empty : {} |
+NonEmpty : Text > ) (< Empty : {} | NonEmpty : Text >.Empty {=}) ) : Text ) ++
+" " ++ x.key ++ " " ++ Integer/show (Natural/toInteger x.cores) ++ " " ++
+Integer/show (Natural/toInteger x.speedFactor) ++ " " ++ ( merge { Empty = λ(_ :
+{}) → "", NonEmpty = λ(result : Text) → result } ( List/fold Text
+x.supportedFeatures < Empty : {} | NonEmpty : Text > ( λ(element : Text) →
+λ(status : < Empty : {} | NonEmpty : Text >) → merge { Empty = λ(_ : {}) → <
+NonEmpty : Text | Empty : {} >.NonEmpty element , NonEmpty = λ(result : Text) →
+< NonEmpty : Text | Empty : {} >.NonEmpty (element ++ "," ++ result) } status :
+< Empty : {} | NonEmpty : Text > ) (< Empty : {} | NonEmpty : Text >.Empty {=})
+) : Text ) ++ " " ++ ( merge { Empty = λ(_ : {}) → "", NonEmpty = λ(result :
+Text) → result } ( List/fold Text x.mandatoryFeatures < Empty : {} | NonEmpty :
+Text > ( λ(element : Text) → λ(status : < Empty : {} | NonEmpty : Text >) →
+merge { Empty = λ(_ : {}) → < NonEmpty : Text | Empty : {} >.NonEmpty element ,
+NonEmpty = λ(result : Text) → < NonEmpty : Text | Empty : {} >.NonEmpty
+(element ++ "," ++ result) } status : < Empty : {} | NonEmpty : Text > ) (<
+Empty : {} | NonEmpty : Text
+>.Empty {=}) ) : Text ) ++ "\n" ++ y ) ""
diff --git a/dhall-lang/Prelude/Bool/and b/dhall-lang/Prelude/Bool/and
--- a/dhall-lang/Prelude/Bool/and
+++ b/dhall-lang/Prelude/Bool/and
@@ -1,18 +1,14 @@
 {-
 The `and` function returns `False` if there are any `False` elements in the
 `List` and returns `True` otherwise
-
-Examples:
-
-```
-./and [ True, False, True ] = False
-
-./and ([] : List Bool) = True
-```
 -}
 let and
     : List Bool → Bool
     =   λ(xs : List Bool)
       → List/fold Bool xs Bool (λ(l : Bool) → λ(r : Bool) → l && r) True
+
+let example0 = assert : and [ True, False, True ] ≡ False
+
+let example1 = assert : and ([] : List Bool) ≡ True
 
 in  and
diff --git a/dhall-lang/Prelude/Bool/build b/dhall-lang/Prelude/Bool/build
--- a/dhall-lang/Prelude/Bool/build
+++ b/dhall-lang/Prelude/Bool/build
@@ -1,17 +1,18 @@
 {-
 `build` is the inverse of `fold`
-
-Examples:
-
-```
-./build (λ(bool : Type) → λ(true : bool) → λ(false : bool) → true) = True
-
-./build (λ(bool : Type) → λ(true : bool) → λ(false : bool) → false) = False
-```
 -}
 let build
     : (∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool) → Bool
     =   λ(f : ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool)
       → f Bool True False
+
+let example0 =
+        assert
+      : build (λ(bool : Type) → λ(true : bool) → λ(false : bool) → true) ≡ True
+
+let example1 =
+        assert
+      :   build (λ(bool : Type) → λ(true : bool) → λ(false : bool) → false)
+        ≡ False
 
 in  build
diff --git a/dhall-lang/Prelude/Bool/even b/dhall-lang/Prelude/Bool/even
--- a/dhall-lang/Prelude/Bool/even
+++ b/dhall-lang/Prelude/Bool/even
@@ -1,22 +1,20 @@
 {-
 Returns `True` if there are an even number of `False` elements in the list and
-returns `False` otherwise
-
-Examples:
-
-```
-./even [ False, True, False ] = True
-
-./even [ False, True ] = False
-
-./even [ False ] = False
+returns `False` otherwise.
 
-./even ([] : List Bool) = True
-```
+This function is the `Monoid` for the `==` operation.
 -}
 let even
     : List Bool → Bool
     =   λ(xs : List Bool)
       → List/fold Bool xs Bool (λ(x : Bool) → λ(y : Bool) → x == y) True
+
+let example0 = assert : even [ False, True, False ] ≡ True
+
+let example1 = assert : even [ False, True ] ≡ False
+
+let example2 = assert : even [ False ] ≡ False
+
+let example3 = assert : even ([] : List Bool) ≡ True
 
 in  even
diff --git a/dhall-lang/Prelude/Bool/fold b/dhall-lang/Prelude/Bool/fold
--- a/dhall-lang/Prelude/Bool/fold
+++ b/dhall-lang/Prelude/Bool/fold
@@ -1,13 +1,5 @@
 {-
 `fold` is essentially the same as `if`/`then`/else` except as a function
-
-Examples:
-
-```
-./fold True Natural 0 1 = 0
-
-./fold False Natural 0 1 = 1
-```
 -}
 let fold
     : ∀(b : Bool) → ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool
@@ -16,5 +8,9 @@
       → λ(true : bool)
       → λ(false : bool)
       → if b then true else false
+
+let example0 = assert : fold True Natural 0 1 ≡ 0
+
+let example1 = assert : fold False Natural 0 1 ≡ 1
 
 in  fold
diff --git a/dhall-lang/Prelude/Bool/not b/dhall-lang/Prelude/Bool/not
--- a/dhall-lang/Prelude/Bool/not
+++ b/dhall-lang/Prelude/Bool/not
@@ -1,12 +1,10 @@
 {-
 Flip the value of a `Bool`
+-}
+let not : Bool → Bool = λ(b : Bool) → b == False
 
-Examples:
+let example0 = assert : not True ≡ False
 
-```
-./not True = False
+let example1 = assert : not False ≡ True
 
-./not False = True
-```
--}
-let not : Bool → Bool = λ(b : Bool) → b == False in not
+in  not
diff --git a/dhall-lang/Prelude/Bool/odd b/dhall-lang/Prelude/Bool/odd
--- a/dhall-lang/Prelude/Bool/odd
+++ b/dhall-lang/Prelude/Bool/odd
@@ -1,22 +1,20 @@
 {-
 Returns `True` if there are an odd number of `True` elements in the list and
-returns `False` otherwise
-
-Examples:
-
-```
-./odd [ True, False, True ] = False
-
-./odd [ True, False ] = True
-
-./odd [ True ] = True
+returns `False` otherwise.
 
-./odd ([] : List Bool) = False
-```
+This function is the `Monoid` for the `!=` operation.
 -}
 let odd
     : List Bool → Bool
     =   λ(xs : List Bool)
       → List/fold Bool xs Bool (λ(x : Bool) → λ(y : Bool) → x != y) False
+
+let example0 = assert : odd [ True, False, True ] ≡ False
+
+let example1 = assert : odd [ True, False ] ≡ True
+
+let example2 = assert : odd [ True ] ≡ True
+
+let example3 = assert : odd ([] : List Bool) ≡ False
 
 in  odd
diff --git a/dhall-lang/Prelude/Bool/or b/dhall-lang/Prelude/Bool/or
--- a/dhall-lang/Prelude/Bool/or
+++ b/dhall-lang/Prelude/Bool/or
@@ -1,18 +1,14 @@
 {-
 The `or` function returns `True` if there are any `True` elements in the `List`
 and returns `False` otherwise
-
-Examples:
-
-```
-./or [ True, False, True ] = True
-
-./or ([] : List Bool) = False
-```
 -}
 let or
     : List Bool → Bool
     =   λ(xs : List Bool)
       → List/fold Bool xs Bool (λ(l : Bool) → λ(r : Bool) → l || r) False
+
+let example0 = assert : or [ True, False, True ] ≡ True
+
+let example1 = assert : or ([] : List Bool) ≡ False
 
 in  or
diff --git a/dhall-lang/Prelude/Bool/show b/dhall-lang/Prelude/Bool/show
--- a/dhall-lang/Prelude/Bool/show
+++ b/dhall-lang/Prelude/Bool/show
@@ -1,13 +1,11 @@
 {-
 Render a `Bool` as `Text` using the same representation as Dhall source code
 (i.e. beginning with a capital letter)
+-}
+let show : Bool → Text = λ(b : Bool) → if b then "True" else "False"
 
-Examples:
+let example0 = assert : show True ≡ "True"
 
-```
-./show True  = "True"
+let example1 = assert : show False ≡ "False"
 
-./show False = "False"
-```
--}
-let show : Bool → Text = λ(b : Bool) → if b then "True" else "False" in show
+in  show
diff --git a/dhall-lang/Prelude/Double/show b/dhall-lang/Prelude/Double/show
--- a/dhall-lang/Prelude/Double/show
+++ b/dhall-lang/Prelude/Double/show
@@ -1,13 +1,11 @@
 {-
 Render a `Double` as `Text` using the same representation as Dhall source
 code (i.e. a decimal floating point number with a leading `-` sign if negative)
+-}
+let show : Double → Text = Double/show
 
-Examples:
+let example0 = assert : show -3.1 ≡ "-3.1"
 
-```
-./show -3.1 = "-3.1"
+let example1 = assert : show 0.4 ≡ "0.4"
 
-./show  0.4 =  "0.4"
-```
--}
-let show : Double → Text = Double/show in show
+in  show
diff --git a/dhall-lang/Prelude/Function/compose b/dhall-lang/Prelude/Function/compose
--- a/dhall-lang/Prelude/Function/compose
+++ b/dhall-lang/Prelude/Function/compose
@@ -1,12 +1,5 @@
 {-
 Compose two functions into one.
-
-Examples:
-
-```
-./compose Natural Natural Bool (λ(n : Natural) → n + n) ../Natural/even 3
-= True
-```
 -}
 let compose
     : ∀(a : Type) → ∀(b : Type) → ∀(c : Type) → (a → b) → (b → c) → a → c
@@ -17,5 +10,10 @@
       → λ(g : B → C)
       → λ(x : A)
       → g (f x)
+
+let example0 =
+        assert
+      :   compose Natural Natural Bool (λ(n : Natural) → n + n) Natural/even 3
+        ≡ True
 
 in  compose
diff --git a/dhall-lang/Prelude/Integer/show b/dhall-lang/Prelude/Integer/show
--- a/dhall-lang/Prelude/Integer/show
+++ b/dhall-lang/Prelude/Integer/show
@@ -2,13 +2,11 @@
 Render an `Integer` as `Text` using the same representation as Dhall source
 code (i.e. a decimal number with a leading `-` sign if negative and a leading
 `+` sign if non-negative)
+-}
+let show : Integer → Text = Integer/show
 
-Examples:
+let example0 = assert : show -3 ≡ "-3"
 
-```
-./show -3 = "-3"
+let example1 = assert : show +0 ≡ "+0"
 
-./show +0 = "+0"
-```
--}
-let show : Integer → Text = Integer/show in show
+in  show
diff --git a/dhall-lang/Prelude/Integer/toDouble b/dhall-lang/Prelude/Integer/toDouble
--- a/dhall-lang/Prelude/Integer/toDouble
+++ b/dhall-lang/Prelude/Integer/toDouble
@@ -1,12 +1,10 @@
 {-
 Convert an `Integer` to the corresponding `Double`
+-}
+let toDouble : Integer → Double = Integer/toDouble
 
-Examples:
+let example0 = assert : toDouble -3 ≡ -3.0
 
-```
-./toDouble -3 = -3.0
+let example1 = assert : toDouble +2 ≡ 2.0
 
-./toDouble +2 = 2.0
-```
--}
-let toDouble : Integer → Double = Integer/toDouble in toDouble
+in  toDouble
diff --git a/dhall-lang/Prelude/JSON/Type b/dhall-lang/Prelude/JSON/Type
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/JSON/Type
@@ -0,0 +1,76 @@
+{- Dhall encoding of an arbitrary JSON value
+
+   For example, the following JSON value:
+
+```
+[ { "foo": null, "bar": [ 1.0, true ] } ]
+```
+
+   ... corresponds to the following Dhall expression:
+
+```
+  λ(JSON : Type)
+→ λ ( json
+    : { array :
+          List JSON → JSON
+      , bool :
+          Bool → JSON
+      , null :
+          JSON
+      , number :
+          Double → JSON
+      , object :
+          List { mapKey : Text, mapValue : JSON } → JSON
+      , string :
+          Text → JSON
+      }
+    )
+→ json.object
+  [ { mapKey = "foo", mapValue = json.null }
+  , { mapKey =
+        "bar"
+    , mapValue =
+        json.array [ json.number 1.0, json.bool True ]
+    }
+  ]
+```
+
+  You do not need to create these values directly, though.  You can use
+  the utilities exported by `./package.dhall` to create values of this type,
+  such as:
+
+```
+let JSON = ./package.dhall
+
+in  JSON.object
+    [ { mapKey = "foo", mapValue = JSON.null }
+    , { mapKey =
+          "bar"
+      , mapValue =
+          JSON.array [ JSON.number 1.0, JSON.bool True ]
+      }
+    ]
+```
+
+-}
+let JSON/Type
+    : Type
+    =   ∀(JSON : Type)
+      → ∀ ( json
+          : { string :
+                Text → JSON
+            , number :
+                Double → JSON
+            , object :
+                List { mapKey : Text, mapValue : JSON } → JSON
+            , array :
+                List JSON → JSON
+            , bool :
+                Bool → JSON
+            , null :
+                JSON
+            }
+          )
+      → JSON
+
+in  JSON/Type
diff --git a/dhall-lang/Prelude/JSON/array b/dhall-lang/Prelude/JSON/array
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/JSON/array
@@ -0,0 +1,43 @@
+{- Create a JSON array from a `List` of JSON values
+
+```
+let JSON = ./package.dhall
+in  JSON.render (JSON.array [ JSON.number 1.0, JSON.bool True ])
+= "[ 1.0, true ]"
+
+let JSON/Type = ./Type
+let JSON = ./package.dhall
+in  JSON.render (JSON.array ([] : List JSON/Type))
+= "[ ]"
+```
+-}
+let JSON =
+        ./Type sha256:5adb234f5868a5b0eddeb034d690aaba8cb94ea20d0d557003e90334fff6be3e
+      ? ./Type
+
+let List/map =
+        ../List/map sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680
+      ? ../List/map
+
+let array
+    : List JSON → JSON
+    =   λ(x : List JSON)
+      → λ(JSON : Type)
+      → λ ( json
+          : { string :
+                Text → JSON
+            , number :
+                Double → JSON
+            , object :
+                List { mapKey : Text, mapValue : JSON } → JSON
+            , array :
+                List JSON → JSON
+            , bool :
+                Bool → JSON
+            , null :
+                JSON
+            }
+          )
+      → json.array (List/map JSON@1 JSON (λ(j : JSON@1) → j JSON json) x)
+
+in  array
diff --git a/dhall-lang/Prelude/JSON/bool b/dhall-lang/Prelude/JSON/bool
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/JSON/bool
@@ -0,0 +1,38 @@
+{- Create a JSON bool from a Dhall `Bool`
+
+```
+let JSON = ./package.dhall
+in  JSON.render (JSON.bool True)
+= "true"
+
+let JSON = ./package.dhall
+in  JSON.render (JSON.bool False)
+= "false"
+```
+-}
+let JSON =
+        ./Type sha256:5adb234f5868a5b0eddeb034d690aaba8cb94ea20d0d557003e90334fff6be3e
+      ? ./Type
+
+let bool
+    : Bool → JSON
+    =   λ(x : Bool)
+      → λ(JSON : Type)
+      → λ ( json
+          : { string :
+                Text → JSON
+            , number :
+                Double → JSON
+            , object :
+                List { mapKey : Text, mapValue : JSON } → JSON
+            , array :
+                List JSON → JSON
+            , bool :
+                Bool → JSON
+            , null :
+                JSON
+            }
+          )
+      → json.bool x
+
+in  bool
diff --git a/dhall-lang/Prelude/JSON/keyText b/dhall-lang/Prelude/JSON/keyText
--- a/dhall-lang/Prelude/JSON/keyText
+++ b/dhall-lang/Prelude/JSON/keyText
@@ -1,17 +1,14 @@
 {-
 Builds a key-value record such that a List of them will be converted to a
 homogeneous record by dhall-to-json and dhall-to-yaml.
+
 Both key and value are fixed to Text.
 Take a look at `Record/keyValue` for a polymorphic version.
-
-Example:
-
-```
-./keyText "foo" "bar" = { mapKey = "foo", mapValue = "bar" }
-```
 -}
-
 let keyText =
       λ(key : Text) → λ(value : Text) → { mapKey = key, mapValue = value }
+
+let example0 =
+      assert : keyText "foo" "bar" ≡ { mapKey = "foo", mapValue = "bar" }
 
 in  keyText
diff --git a/dhall-lang/Prelude/JSON/keyValue b/dhall-lang/Prelude/JSON/keyValue
--- a/dhall-lang/Prelude/JSON/keyValue
+++ b/dhall-lang/Prelude/JSON/keyValue
@@ -1,20 +1,17 @@
 {-
 Builds a key-value record such that a List of them will be converted to a
 homogeneous record by dhall-to-json and dhall-to-yaml.
-
-Examples:
-
-```
-./keyValue Natural "foo" 2 = { mapKey = "foo", mapValue = 2 }
-
-./keyValue Text "bar" "baz" = { mapKey = "bar", mapValue = "baz" }
-```
 -}
-
 let keyValue =
         λ(v : Type)
       → λ(key : Text)
       → λ(value : v)
       → { mapKey = key, mapValue = value }
+
+let example0 =
+      assert : keyValue Natural "foo" 2 ≡ { mapKey = "foo", mapValue = 2 }
+
+let example1 =
+      assert : keyValue Text "bar" "baz" ≡ { mapKey = "bar", mapValue = "baz" }
 
 in  keyValue
diff --git a/dhall-lang/Prelude/JSON/null b/dhall-lang/Prelude/JSON/null
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/JSON/null
@@ -0,0 +1,33 @@
+{- Create a JSON null
+
+```
+let JSON = ./package.dhall
+in  JSON.render JSON.null
+= "null"
+```
+-}
+let JSON =
+        ./Type sha256:5adb234f5868a5b0eddeb034d690aaba8cb94ea20d0d557003e90334fff6be3e
+      ? ./Type
+
+let null
+    : JSON
+    =   λ(JSON : Type)
+      → λ ( json
+          : { string :
+                Text → JSON
+            , number :
+                Double → JSON
+            , object :
+                List { mapKey : Text, mapValue : JSON } → JSON
+            , array :
+                List JSON → JSON
+            , bool :
+                Bool → JSON
+            , null :
+                JSON
+            }
+          )
+      → json.null
+
+in  null
diff --git a/dhall-lang/Prelude/JSON/number b/dhall-lang/Prelude/JSON/number
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/JSON/number
@@ -0,0 +1,38 @@
+{- Create a JSON number from a Dhall `Double`
+
+```
+let JSON = ./package.dhall
+in  JSON.render (JSON.number 42.0)
+= "42.0"
+
+let JSON = ./package.dhall
+in  JSON.render (JSON.number -1.5e-10)
+= "-1.5e-10"
+```
+-}
+let JSON =
+        ./Type sha256:5adb234f5868a5b0eddeb034d690aaba8cb94ea20d0d557003e90334fff6be3e
+      ? ./Type
+
+let number
+    : Double → JSON
+    =   λ(x : Double)
+      → λ(JSON : Type)
+      → λ ( json
+          : { string :
+                Text → JSON
+            , number :
+                Double → JSON
+            , object :
+                List { mapKey : Text, mapValue : JSON } → JSON
+            , array :
+                List JSON → JSON
+            , bool :
+                Bool → JSON
+            , null :
+                JSON
+            }
+          )
+      → json.number x
+
+in  number
diff --git a/dhall-lang/Prelude/JSON/object b/dhall-lang/Prelude/JSON/object
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/JSON/object
@@ -0,0 +1,57 @@
+{- Create a JSON object from a Dhall `Map`
+
+```
+let JSON = ./package.dhall
+in  JSON.render
+    ( JSON.object
+      [ { mapKey = "foo", mapValue = JSON.number 1.0 }
+      , { mapKey = "bar", mapValue = JSON.bool True  }
+      ]
+    )
+= "{ \"foo\": 1.0, \"bar\": true }"
+
+let JSON/Type = ./Type
+let JSON = ./package.dhall
+in  JSON.render
+    (JSON.object ([] : List { mapKey : Text, mapValue : JSON/Type }))
+= "{ }"
+```
+-}
+let JSON =
+        ./Type sha256:5adb234f5868a5b0eddeb034d690aaba8cb94ea20d0d557003e90334fff6be3e
+      ? ./Type
+
+let List/map =
+        ../List/map sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680
+      ? ../List/map
+
+let object
+    : List { mapKey : Text, mapValue : JSON } → JSON
+    =   λ(x : List { mapKey : Text, mapValue : JSON })
+      → λ(JSON : Type)
+      → λ ( json
+          : { string :
+                Text → JSON
+            , number :
+                Double → JSON
+            , object :
+                List { mapKey : Text, mapValue : JSON } → JSON
+            , array :
+                List JSON → JSON
+            , bool :
+                Bool → JSON
+            , null :
+                JSON
+            }
+          )
+      → json.object
+          ( List/map
+              { mapKey : Text, mapValue : JSON@1 }
+              { mapKey : Text, mapValue : JSON }
+              (   λ(kv : { mapKey : Text, mapValue : JSON@1 })
+                → { mapKey = kv.mapKey, mapValue = kv.mapValue JSON json }
+              )
+              x
+          )
+
+in  object
diff --git a/dhall-lang/Prelude/JSON/render b/dhall-lang/Prelude/JSON/render
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/JSON/render
@@ -0,0 +1,62 @@
+{- Render a `JSON` value as `Text`
+
+   This is useful for debugging `JSON` values or for tests.  For anything
+   more sophisticated you should use `dhall-to-json` or `dhall-to-yaml`
+
+```
+let JSON = ./package.dhall
+
+in  JSON.render
+    ( JSON.array
+      [ JSON.bool True
+      , JSON.string "Hello"
+      , JSON.object
+        [ { mapKey = "foo", mapValue = JSON.null       }
+        , { mapKey = "bar", mapValue = JSON.number 1.0 }
+        ]
+      ]
+    )
+= "[ true, \"Hello\", { \"foo\": null, \"bar\": 1.0 } ]"
+```
+-}
+let JSON =
+        ./Type sha256:5adb234f5868a5b0eddeb034d690aaba8cb94ea20d0d557003e90334fff6be3e
+      ? ./Type
+
+let Text/concatMapSep =
+        ../Text/concatMapSep sha256:c272aca80a607bc5963d1fcb38819e7e0d3e72ac4d02b1183b1afb6a91340840
+      ? ../Text/concatMapSep
+
+let render
+    : JSON → Text
+    =   λ(j : JSON)
+      → j
+          Text
+          { string =
+              λ(x : Text) → Text/show x
+          , number =
+              λ(x : Double) → Double/show x
+          , object =
+                λ(x : List { mapKey : Text, mapValue : Text })
+              → let body =
+                      Text/concatMapSep
+                        ","
+                        { mapKey : Text, mapValue : Text }
+                        (   λ(e : { mapKey : Text, mapValue : Text })
+                          → " ${Text/show e.mapKey}: ${e.mapValue}"
+                        )
+                        x
+                
+                in  "{${body} }"
+          , array =
+                λ(x : List Text)
+              → let body = Text/concatMapSep "," Text (λ(y : Text) → " ${y}") x
+                
+                in  "[${body} ]"
+          , bool =
+              λ(x : Bool) → if x then "true" else "false"
+          , null =
+              "null"
+          }
+
+in  render
diff --git a/dhall-lang/Prelude/JSON/string b/dhall-lang/Prelude/JSON/string
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/JSON/string
@@ -0,0 +1,38 @@
+{- Create a JSON string from Dhall `Text`
+
+```
+let JSON = ./package.dhall
+in  JSON.render (JSON.string "ABC $ \" 🙂")
+= "\"ABC \\u0024 \\\" 🙂\""
+
+let JSON = ./package.dhall
+in  JSON.render (JSON.string "")
+= "\"\""
+```
+-}
+let JSON =
+        ./Type sha256:5adb234f5868a5b0eddeb034d690aaba8cb94ea20d0d557003e90334fff6be3e
+      ? ./Type
+
+let string
+    : Text → JSON
+    =   λ(x : Text)
+      → λ(JSON : Type)
+      → λ ( json
+          : { string :
+                Text → JSON
+            , number :
+                Double → JSON
+            , object :
+                List { mapKey : Text, mapValue : JSON } → JSON
+            , array :
+                List JSON → JSON
+            , bool :
+                Bool → JSON
+            , null :
+                JSON
+            }
+          )
+      → json.string x
+
+in  string
diff --git a/dhall-lang/Prelude/List/all b/dhall-lang/Prelude/List/all
--- a/dhall-lang/Prelude/List/all
+++ b/dhall-lang/Prelude/List/all
@@ -1,14 +1,6 @@
 {-
 Returns `True` if the supplied function returns `True` for all elements in the
 `List`
-
-Examples:
-
-```
-./all Natural Natural/even [ 2, 3, 5 ] = False
-
-./all Natural Natural/even ([] : List Natural) = True
-```
 -}
 let all
     : ∀(a : Type) → (a → Bool) → List a → Bool
@@ -16,5 +8,9 @@
       → λ(f : a → Bool)
       → λ(xs : List a)
       → List/fold a xs Bool (λ(x : a) → λ(r : Bool) → f x && r) True
+
+let example0 = assert : all Natural Natural/even [ 2, 3, 5 ] ≡ False
+
+let example1 = assert : all Natural Natural/even ([] : List Natural) ≡ True
 
 in  all
diff --git a/dhall-lang/Prelude/List/any b/dhall-lang/Prelude/List/any
--- a/dhall-lang/Prelude/List/any
+++ b/dhall-lang/Prelude/List/any
@@ -1,14 +1,6 @@
 {-
 Returns `True` if the supplied function returns `True` for any element in the
 `List`
-
-Examples:
-
-```
-./any Natural Natural/even [ 2, 3, 5 ] = True
-
-./any Natural Natural/even ([] : List Natural) = False
-```
 -}
 let any
     : ∀(a : Type) → (a → Bool) → List a → Bool
@@ -16,5 +8,9 @@
       → λ(f : a → Bool)
       → λ(xs : List a)
       → List/fold a xs Bool (λ(x : a) → λ(r : Bool) → f x || r) False
+
+let example0 = assert : any Natural Natural/even [ 2, 3, 5 ] ≡ True
+
+let example1 = assert : any Natural Natural/even ([] : List Natural) ≡ False
 
 in  any
diff --git a/dhall-lang/Prelude/List/build b/dhall-lang/Prelude/List/build
--- a/dhall-lang/Prelude/List/build
+++ b/dhall-lang/Prelude/List/build
@@ -1,32 +1,32 @@
 {-
 `build` is the inverse of `fold`
-
-Examples:
-
-```
-./build
-Text
-(   λ(list : Type)
-→   λ(cons : Text → list → list)
-→   λ(nil : list)
-→   cons "ABC" (cons "DEF" nil)
-)
-= [ "ABC", "DEF" ]
-
-./build
-Text
-(   λ(list : Type)
-→   λ(cons : Text → list → list)
-→   λ(nil : list)
-→   nil
-)
-= [] : List Text
-```
 -}
 let build
     :   ∀(a : Type)
       → (∀(list : Type) → ∀(cons : a → list → list) → ∀(nil : list) → list)
       → List a
     = List/build
+
+let example0 =
+        assert
+      :   build
+            Text
+            (   λ(list : Type)
+              → λ(cons : Text → list → list)
+              → λ(nil : list)
+              → cons "ABC" (cons "DEF" nil)
+            )
+        ≡ [ "ABC", "DEF" ]
+
+let example1 =
+        assert
+      :   build
+            Text
+            (   λ(list : Type)
+              → λ(cons : Text → list → list)
+              → λ(nil : list)
+              → nil
+            )
+        ≡ ([] : List Text)
 
 in  build
diff --git a/dhall-lang/Prelude/List/concat b/dhall-lang/Prelude/List/concat
--- a/dhall-lang/Prelude/List/concat
+++ b/dhall-lang/Prelude/List/concat
@@ -1,42 +1,36 @@
 {-
 Concatenate a `List` of `List`s into a single `List`
-
-Examples:
-
-```
-./concat Natural
-[   [0, 1, 2]
-,   [3, 4]
-,   [5, 6, 7, 8]
-]
-= [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
-
-./concat Natural
-(   [   [] : List Natural
-    ,   [] : List Natural
-    ,   [] : List Natural
-    ]
-)
-= [] : List Natural
-
-./concat Natural ([] : List (List Natural)) = [] : List Natural
-```
 -}
 let concat
     : ∀(a : Type) → List (List a) → List a
     =   λ(a : Type)
       → λ(xss : List (List a))
       → List/build
-        a
-        (   λ(list : Type)
-          → λ(cons : a → list → list)
-          → λ(nil : list)
-          → List/fold
-            (List a)
-            xss
-            list
-            (λ(xs : List a) → λ(ys : list) → List/fold a xs list cons ys)
-            nil
-        )
+          a
+          (   λ(list : Type)
+            → λ(cons : a → list → list)
+            → λ(nil : list)
+            → List/fold
+                (List a)
+                xss
+                list
+                (λ(xs : List a) → λ(ys : list) → List/fold a xs list cons ys)
+                nil
+          )
+
+let example0 =
+        assert
+      :   concat Natural [ [ 0, 1, 2 ], [ 3, 4 ], [ 5, 6, 7, 8 ] ]
+        ≡ [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
+
+let example1 =
+        assert
+      :   concat
+            Natural
+            [ [] : List Natural, [] : List Natural, [] : List Natural ]
+        ≡ ([] : List Natural)
+
+let example2 =
+      assert : concat Natural ([] : List (List Natural)) ≡ ([] : List Natural)
 
 in  concat
diff --git a/dhall-lang/Prelude/List/concatMap b/dhall-lang/Prelude/List/concatMap
--- a/dhall-lang/Prelude/List/concatMap
+++ b/dhall-lang/Prelude/List/concatMap
@@ -1,16 +1,6 @@
 {-
 Transform a list by applying a function to each element and flattening the
 results
-
-Examples:
-
-```
-./concatMap Natural Natural (λ(n : Natural) → [n, n]) [2, 3, 5]
-= [ 2, 2, 3, 3, 5, 5 ]
-
-./concatMap Natural Natural (λ(n : Natural) → [n, n]) ([] : List Natural)
-= [] : List Natural
-```
 -}
 let concatMap
     : ∀(a : Type) → ∀(b : Type) → (a → List b) → List a → List b
@@ -19,10 +9,24 @@
       → λ(f : a → List b)
       → λ(xs : List a)
       → List/build
-        b
-        (   λ(list : Type)
-          → λ(cons : b → list → list)
-          → List/fold a xs list (λ(x : a) → List/fold b (f x) list cons)
-        )
+          b
+          (   λ(list : Type)
+            → λ(cons : b → list → list)
+            → List/fold a xs list (λ(x : a) → List/fold b (f x) list cons)
+          )
+
+let example0 =
+        assert
+      :   concatMap Natural Natural (λ(n : Natural) → [ n, n ]) [ 2, 3, 5 ]
+        ≡ [ 2, 2, 3, 3, 5, 5 ]
+
+let example1 =
+        assert
+      :   concatMap
+            Natural
+            Natural
+            (λ(n : Natural) → [ n, n ])
+            ([] : List Natural)
+        ≡ ([] : List Natural)
 
 in  concatMap
diff --git a/dhall-lang/Prelude/List/filter b/dhall-lang/Prelude/List/filter
--- a/dhall-lang/Prelude/List/filter
+++ b/dhall-lang/Prelude/List/filter
@@ -2,14 +2,6 @@
 Only keep elements of the list where the supplied function returns `True`
 
 Examples:
-
-```
-./filter Natural Natural/even [ 2, 3, 5 ]
-= [ 2 ]
-
-./filter Natural Natural/odd [ 2, 3, 5 ]
-= [ 3, 5 ]
-```
 -}
 let filter
     : ∀(a : Type) → (a → Bool) → List a → List a
@@ -17,14 +9,18 @@
       → λ(f : a → Bool)
       → λ(xs : List a)
       → List/build
-        a
-        (   λ(list : Type)
-          → λ(cons : a → list → list)
-          → List/fold
-            a
-            xs
-            list
-            (λ(x : a) → λ(xs : list) → if f x then cons x xs else xs)
-        )
+          a
+          (   λ(list : Type)
+            → λ(cons : a → list → list)
+            → List/fold
+                a
+                xs
+                list
+                (λ(x : a) → λ(xs : list) → if f x then cons x xs else xs)
+          )
+
+let example0 = assert : filter Natural Natural/even [ 2, 3, 5 ] ≡ [ 2 ]
+
+let example1 = assert : filter Natural Natural/odd [ 2, 3, 5 ] ≡ [ 3, 5 ]
 
 in  filter
diff --git a/dhall-lang/Prelude/List/fold b/dhall-lang/Prelude/List/fold
--- a/dhall-lang/Prelude/List/fold
+++ b/dhall-lang/Prelude/List/fold
@@ -3,36 +3,6 @@
 
 If you treat the list `[ x, y, z ]` as `cons x (cons y (cons z nil))`, then a
 `fold` just replaces each `cons` and `nil` with something else
-
-Examples:
-
-```
-    ./fold
-    Natural
-    [ 2, 3, 5 ]
-    Natural
-    (λ(x : Natural) → λ(y : Natural) → x + y)
-    0
-=   10
-
-    λ(nil : Natural)
-→   ./fold
-    Natural
-    [ 2, 3, 5 ]
-    Natural
-    (λ(x : Natural) → λ(y : Natural) → x + y)
-    nil
-=   λ(nil : Natural) → 2 + (3 + (5 + nil))
-
-    λ(list : Type)
-→   λ(cons : Natural → list → list)
-→   λ(nil : list)
-→   ./fold Natural [ 2, 3, 5 ] list cons nil
-=   λ(list : Type)
-→   λ(cons : Natural → list → list)
-→   λ(nil : list)
-→   cons 2 (cons 3 (cons 5 nil))
-```
 -}
 let fold
     :   ∀(a : Type)
@@ -42,5 +12,40 @@
       → ∀(nil : list)
       → list
     = List/fold
+
+let example0 =
+        assert
+      :   fold
+            Natural
+            [ 2, 3, 5 ]
+            Natural
+            (λ(x : Natural) → λ(y : Natural) → x + y)
+            0
+        ≡ 10
+
+let example1 =
+        assert
+      :   (   λ(nil : Natural)
+            → fold
+                Natural
+                [ 2, 3, 5 ]
+                Natural
+                (λ(x : Natural) → λ(y : Natural) → x + y)
+                nil
+          )
+        ≡ (λ(nil : Natural) → 2 + (3 + (5 + nil)))
+
+let example2 =
+        assert
+      :   (   λ(list : Type)
+            → λ(cons : Natural → list → list)
+            → λ(nil : list)
+            → fold Natural [ 2, 3, 5 ] list cons nil
+          )
+        ≡ (   λ(list : Type)
+            → λ(cons : Natural → list → list)
+            → λ(nil : list)
+            → cons 2 (cons 3 (cons 5 nil))
+          )
 
 in  fold
diff --git a/dhall-lang/Prelude/List/generate b/dhall-lang/Prelude/List/generate
--- a/dhall-lang/Prelude/List/generate
+++ b/dhall-lang/Prelude/List/generate
@@ -1,14 +1,6 @@
 {-
 Build a list by calling the supplied function on all `Natural` numbers from `0`
 up to but not including the supplied `Natural` number
-
-Examples:
-
-```
-./generate 5 Bool Natural/even = [ True, False, True, False, True ]
-
-./generate 0 Bool Natural/even = [] : List Bool
-```
 -}
 let generate
     : Natural → ∀(a : Type) → (Natural → a) → List a
@@ -16,23 +8,28 @@
       → λ(a : Type)
       → λ(f : Natural → a)
       → List/build
-        a
-        (   λ(list : Type)
-          → λ(cons : a → list → list)
-          → List/fold
-            { index : Natural, value : {} }
-            ( List/indexed
-              {}
-              ( List/build
-                {}
-                (   λ(list : Type)
-                  → λ(cons : {} → list → list)
-                  → Natural/fold n list (cons {=})
+          a
+          (   λ(list : Type)
+            → λ(cons : a → list → list)
+            → List/fold
+                { index : Natural, value : {} }
+                ( List/indexed
+                    {}
+                    ( List/build
+                        {}
+                        (   λ(list : Type)
+                          → λ(cons : {} → list → list)
+                          → Natural/fold n list (cons {=})
+                        )
+                    )
                 )
-              )
-            )
-            list
-            (λ(x : { index : Natural, value : {} }) → cons (f x.index))
-        )
+                list
+                (λ(x : { index : Natural, value : {} }) → cons (f x.index))
+          )
+
+let example0 =
+      assert : generate 5 Bool Natural/even ≡ [ True, False, True, False, True ]
+
+let example1 = assert : generate 0 Bool Natural/even ≡ ([] : List Bool)
 
 in  generate
diff --git a/dhall-lang/Prelude/List/head b/dhall-lang/Prelude/List/head
--- a/dhall-lang/Prelude/List/head
+++ b/dhall-lang/Prelude/List/head
@@ -1,12 +1,10 @@
 {-
 Retrieve the first element of the list
+-}
+let head : ∀(a : Type) → List a → Optional a = List/head
 
-Examples:
+let example0 = assert : head Natural [ 0, 1, 2 ] ≡ Some 0
 
-```
-./head Natural [ 0, 1, 2 ] = Some 0
+let example1 = assert : head Natural ([] : List Natural) ≡ None Natural
 
-./head Natural ([] : List Natural) = None Natural
-```
--}
-let head : ∀(a : Type) → List a → Optional a = List/head in head
+in  head
diff --git a/dhall-lang/Prelude/List/indexed b/dhall-lang/Prelude/List/indexed
--- a/dhall-lang/Prelude/List/indexed
+++ b/dhall-lang/Prelude/List/indexed
@@ -1,21 +1,21 @@
 {-
 Tag each element of the list with its index
-
-Examples:
-
-```
-./indexed Bool [ True, False, True ]
-=   [   { index = 0, value = True  }
-    ,   { index = 1, value = False }
-    ,   { index = 2, value = True  }
-    ] : List { index : Natural, value : Bool }
-
-./indexed Bool ([] : List Bool)
-= [] : List { index : Natural, value : Bool }
-```
 -}
 let indexed
     : ∀(a : Type) → List a → List { index : Natural, value : a }
     = List/indexed
+
+let example0 =
+        assert
+      :   indexed Bool [ True, False, True ]
+        ≡ [ { index = 0, value = True }
+          , { index = 1, value = False }
+          , { index = 2, value = True }
+          ]
+
+let example1 =
+        assert
+      :   indexed Bool ([] : List Bool)
+        ≡ ([] : List { index : Natural, value : Bool })
 
 in  indexed
diff --git a/dhall-lang/Prelude/List/iterate b/dhall-lang/Prelude/List/iterate
--- a/dhall-lang/Prelude/List/iterate
+++ b/dhall-lang/Prelude/List/iterate
@@ -1,16 +1,6 @@
 {-
 Generate a list of the specified length given a seed value and transition
 function
-
-Examples:
-
-```
-./iterate 10 Natural (λ(x : Natural) → x * 2) 1
-= [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 ]
-
-./iterate 0 Natural (λ(x : Natural) → x * 2) 1
-= [] : List Natural
-```
 -}
 let iterate
     : Natural → ∀(a : Type) → (a → a) → a → List a
@@ -19,25 +9,34 @@
       → λ(f : a → a)
       → λ(x : a)
       → List/build
-        a
-        (   λ(list : Type)
-          → λ(cons : a → list → list)
-          → List/fold
-            { index : Natural, value : {} }
-            ( List/indexed
-              {}
-              ( List/build
-                {}
-                (   λ(list : Type)
-                  → λ(cons : {} → list → list)
-                  → Natural/fold n list (cons {=})
+          a
+          (   λ(list : Type)
+            → λ(cons : a → list → list)
+            → List/fold
+                { index : Natural, value : {} }
+                ( List/indexed
+                    {}
+                    ( List/build
+                        {}
+                        (   λ(list : Type)
+                          → λ(cons : {} → list → list)
+                          → Natural/fold n list (cons {=})
+                        )
+                    )
                 )
-              )
-            )
-            list
-            (   λ(y : { index : Natural, value : {} })
-              → cons (Natural/fold y.index a f x)
-            )
-        )
+                list
+                (   λ(y : { index : Natural, value : {} })
+                  → cons (Natural/fold y.index a f x)
+                )
+          )
+
+let example0 =
+        assert
+      :   iterate 10 Natural (λ(x : Natural) → x * 2) 1
+        ≡ [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 ]
+
+let example1 =
+        assert
+      : iterate 0 Natural (λ(x : Natural) → x * 2) 1 ≡ ([] : List Natural)
 
 in  iterate
diff --git a/dhall-lang/Prelude/List/last b/dhall-lang/Prelude/List/last
--- a/dhall-lang/Prelude/List/last
+++ b/dhall-lang/Prelude/List/last
@@ -1,12 +1,10 @@
 {-
 Retrieve the last element of the list
+-}
+let last : ∀(a : Type) → List a → Optional a = List/last
 
-Examples:
+let example0 = assert : last Natural [ 0, 1, 2 ] ≡ Some 2
 
-```
-./last Natural [ 0, 1, 2 ] = Some 2
+let example1 = assert : last Natural ([] : List Natural) ≡ None Natural
 
-./last Natural ([] : List Natural) = None Natural
-```
--}
-let last : ∀(a : Type) → List a → Optional a = List/last in last
+in  last
diff --git a/dhall-lang/Prelude/List/length b/dhall-lang/Prelude/List/length
--- a/dhall-lang/Prelude/List/length
+++ b/dhall-lang/Prelude/List/length
@@ -1,12 +1,10 @@
 {-
 Returns the number of elements in a list
+-}
+let length : ∀(a : Type) → List a → Natural = List/length
 
-Examples:
+let example0 = assert : length Natural [ 0, 1, 2 ] ≡ 3
 
-```
-./length Natural [ 0, 1, 2 ] = 3
+let example1 = assert : length Natural ([] : List Natural) ≡ 0
 
-./length Natural ([] : List Natural) = 0
-```
--}
-let length : ∀(a : Type) → List a → Natural = List/length in length
+in  length
diff --git a/dhall-lang/Prelude/List/map b/dhall-lang/Prelude/List/map
--- a/dhall-lang/Prelude/List/map
+++ b/dhall-lang/Prelude/List/map
@@ -1,15 +1,5 @@
 {-
 Transform a list by applying a function to each element
-
-Examples:
-
-```
-./map Natural Bool Natural/even [ 2, 3, 5 ]
-= [ True, False, False ]
-
-./map Natural Bool Natural/even ([] : List Natural)
-= [] : List Bool
-```
 -}
 let map
     : ∀(a : Type) → ∀(b : Type) → (a → b) → List a → List b
@@ -18,10 +8,18 @@
       → λ(f : a → b)
       → λ(xs : List a)
       → List/build
-        b
-        (   λ(list : Type)
-          → λ(cons : b → list → list)
-          → List/fold a xs list (λ(x : a) → cons (f x))
-        )
+          b
+          (   λ(list : Type)
+            → λ(cons : b → list → list)
+            → List/fold a xs list (λ(x : a) → cons (f x))
+          )
+
+let example0 =
+        assert
+      : map Natural Bool Natural/even [ 2, 3, 5 ] ≡ [ True, False, False ]
+
+let example1 =
+        assert
+      : map Natural Bool Natural/even ([] : List Natural) ≡ ([] : List Bool)
 
 in  map
diff --git a/dhall-lang/Prelude/List/null b/dhall-lang/Prelude/List/null
--- a/dhall-lang/Prelude/List/null
+++ b/dhall-lang/Prelude/List/null
@@ -1,16 +1,12 @@
 {-
 Returns `True` if the `List` is empty and `False` otherwise
-
-Examples:
-
-```
-./null Natural [ 0, 1, 2 ] = False
-
-./null Natural ([] : List Natural) = True
-```
 -}
 let null
     : ∀(a : Type) → List a → Bool
     = λ(a : Type) → λ(xs : List a) → Natural/isZero (List/length a xs)
+
+let example0 = assert : null Natural [ 0, 1, 2 ] ≡ False
+
+let example1 = assert : null Natural ([] : List Natural) ≡ True
 
 in  null
diff --git a/dhall-lang/Prelude/List/replicate b/dhall-lang/Prelude/List/replicate
--- a/dhall-lang/Prelude/List/replicate
+++ b/dhall-lang/Prelude/List/replicate
@@ -1,13 +1,5 @@
 {-
 Build a list by copying the given element the specified number of times
-
-Examples:
-
-```
-./replicate 9 Natural 1 = [ 1, 1, 1, 1, 1, 1, 1, 1, 1 ]
-
-./replicate 0 Natural 1 = [] : List Natural
-```
 -}
 let replicate
     : Natural → ∀(a : Type) → a → List a
@@ -15,10 +7,14 @@
       → λ(a : Type)
       → λ(x : a)
       → List/build
-        a
-        (   λ(list : Type)
-          → λ(cons : a → list → list)
-          → Natural/fold n list (cons x)
-        )
+          a
+          (   λ(list : Type)
+            → λ(cons : a → list → list)
+            → Natural/fold n list (cons x)
+          )
+
+let example0 = assert : replicate 9 Natural 1 ≡ [ 1, 1, 1, 1, 1, 1, 1, 1, 1 ]
+
+let example1 = assert : replicate 0 Natural 1 ≡ ([] : List Natural)
 
 in  replicate
diff --git a/dhall-lang/Prelude/List/reverse b/dhall-lang/Prelude/List/reverse
--- a/dhall-lang/Prelude/List/reverse
+++ b/dhall-lang/Prelude/List/reverse
@@ -1,12 +1,11 @@
 {-
 Reverse a list
+-}
+let reverse : ∀(a : Type) → List a → List a = List/reverse
 
-Examples:
+let example0 = assert : reverse Natural [ 0, 1, 2 ] ≡ [ 2, 1, 0 ]
 
-```
-./reverse Natural [ 0, 1, 2 ] = [ 2, 1, 0 ] : List Natural
+let example1 =
+      assert : reverse Natural ([] : List Natural) ≡ ([] : List Natural)
 
-./reverse Natural ([] : List Natural) = [] : List Natural
-```
--}
-let reverse : ∀(a : Type) → List a → List a = List/reverse in reverse
+in  reverse
diff --git a/dhall-lang/Prelude/List/shifted b/dhall-lang/Prelude/List/shifted
--- a/dhall-lang/Prelude/List/shifted
+++ b/dhall-lang/Prelude/List/shifted
@@ -1,39 +1,6 @@
 {-
 Combine a `List` of `List`s, offsetting the `index` of each element by the
 number of elements in preceding lists
-
-Examples:
-
-```
-./shifted
-Bool
-[   [   { index = 0, value = True  }
-    ,   { index = 1, value = True  }
-    ,   { index = 2, value = True  }
-    ]
-,   [   { index = 0, value = False }
-    ,   { index = 1, value = False }
-    ]
-,   [   { index = 0, value = True  }
-    ,   { index = 1, value = True  }
-    ,   { index = 2, value = True  }
-    ,   { index = 3, value = True  }
-    ]
-]
-=   [   { index = 0, value = True  }
-    ,   { index = 1, value = True  }
-    ,   { index = 2, value = True  }
-    ,   { index = 3, value = False }
-    ,   { index = 4, value = False }
-    ,   { index = 5, value = True  }
-    ,   { index = 6, value = True  }
-    ,   { index = 7, value = True  }
-    ,   { index = 8, value = True  }
-    ]
-
-./shifted Bool ([] : List (List { index : Natural, value : Bool }))
-= [] : List { index : Natural, value : Bool }
-```
 -}
 let shifted
     :   ∀(a : Type)
@@ -42,45 +9,78 @@
     =   λ(a : Type)
       → λ(kvss : List (List { index : Natural, value : a }))
       → List/build
-        { index : Natural, value : a }
-        (   λ(list : Type)
-          → λ(cons : { index : Natural, value : a } → list → list)
-          → λ(nil : list)
-          → let result =
-                  List/fold
-                  (List { index : Natural, value : a })
-                  kvss
-                  { count : Natural, diff : Natural → list }
-                  (   λ(kvs : List { index : Natural, value : a })
-                    → λ(y : { count : Natural, diff : Natural → list })
-                    → let length =
-                            List/length { index : Natural, value : a } kvs
-                      
-                      in  { count =
-                              y.count + length
-                          , diff =
-                                λ(n : Natural)
-                              → List/fold
-                                { index : Natural, value : a }
-                                kvs
-                                list
-                                (   λ(kvOld : { index : Natural, value : a })
-                                  → λ(z : list)
-                                  → let kvNew =
-                                          { index =
-                                              kvOld.index + n
-                                          , value =
-                                              kvOld.value
-                                          }
-                                    
-                                    in  cons kvNew z
-                                )
-                                (y.diff (n + length))
-                          }
-                  )
-                  { count = 0, diff = λ(_ : Natural) → nil }
-            
-            in  result.diff 0
-        )
+          { index : Natural, value : a }
+          (   λ(list : Type)
+            → λ(cons : { index : Natural, value : a } → list → list)
+            → λ(nil : list)
+            → let result =
+                    List/fold
+                      (List { index : Natural, value : a })
+                      kvss
+                      { count : Natural, diff : Natural → list }
+                      (   λ(kvs : List { index : Natural, value : a })
+                        → λ(y : { count : Natural, diff : Natural → list })
+                        → let length =
+                                List/length { index : Natural, value : a } kvs
+                          
+                          in  { count =
+                                  y.count + length
+                              , diff =
+                                    λ(n : Natural)
+                                  → List/fold
+                                      { index : Natural, value : a }
+                                      kvs
+                                      list
+                                      (   λ ( kvOld
+                                            : { index : Natural, value : a }
+                                            )
+                                        → λ(z : list)
+                                        → let kvNew =
+                                                { index =
+                                                    kvOld.index + n
+                                                , value =
+                                                    kvOld.value
+                                                }
+                                          
+                                          in  cons kvNew z
+                                      )
+                                      (y.diff (n + length))
+                              }
+                      )
+                      { count = 0, diff = λ(_ : Natural) → nil }
+              
+              in  result.diff 0
+          )
+
+let example0 =
+        assert
+      :   shifted
+            Bool
+            [ [ { index = 0, value = True }
+              , { index = 1, value = True }
+              , { index = 2, value = True }
+              ]
+            , [ { index = 0, value = False }, { index = 1, value = False } ]
+            , [ { index = 0, value = True }
+              , { index = 1, value = True }
+              , { index = 2, value = True }
+              , { index = 3, value = True }
+              ]
+            ]
+        ≡ [ { index = 0, value = True }
+          , { index = 1, value = True }
+          , { index = 2, value = True }
+          , { index = 3, value = False }
+          , { index = 4, value = False }
+          , { index = 5, value = True }
+          , { index = 6, value = True }
+          , { index = 7, value = True }
+          , { index = 8, value = True }
+          ]
+
+let example1 =
+        assert
+      :   shifted Bool ([] : List (List { index : Natural, value : Bool }))
+        ≡ ([] : List { index : Natural, value : Bool })
 
 in  shifted
diff --git a/dhall-lang/Prelude/List/unzip b/dhall-lang/Prelude/List/unzip
--- a/dhall-lang/Prelude/List/unzip
+++ b/dhall-lang/Prelude/List/unzip
@@ -1,24 +1,5 @@
 {-
 Unzip a `List` into two separate `List`s
-
-Examples:
-
-```
-./unzip
-Text
-Bool
-(   [   { _1 = "ABC", _2 = True  }
-    ,   { _1 = "DEF", _2 = False }
-    ,   { _1 = "GHI", _2 = True  }
-    ]
-)
-=   { _1 = [ "ABC", "DEF", "GHI" ]
-    , _2 = [ True, False, True ]
-    }
-
-./unzip Text Bool ([] : List { _1 : Text, _2 : Bool })
-= { _1 = [] : List Text, _2 = [] : List Bool }
-```
 -}
 let unzip
     :   ∀(a : Type)
@@ -30,26 +11,42 @@
       → λ(xs : List { _1 : a, _2 : b })
       → { _1 =
             List/build
-            a
-            (   λ(list : Type)
-              → λ(cons : a → list → list)
-              → List/fold
-                { _1 : a, _2 : b }
-                xs
-                list
-                (λ(x : { _1 : a, _2 : b }) → cons x._1)
-            )
+              a
+              (   λ(list : Type)
+                → λ(cons : a → list → list)
+                → List/fold
+                    { _1 : a, _2 : b }
+                    xs
+                    list
+                    (λ(x : { _1 : a, _2 : b }) → cons x._1)
+              )
         , _2 =
             List/build
-            b
-            (   λ(list : Type)
-              → λ(cons : b → list → list)
-              → List/fold
-                { _1 : a, _2 : b }
-                xs
-                list
-                (λ(x : { _1 : a, _2 : b }) → cons x._2)
-            )
+              b
+              (   λ(list : Type)
+                → λ(cons : b → list → list)
+                → List/fold
+                    { _1 : a, _2 : b }
+                    xs
+                    list
+                    (λ(x : { _1 : a, _2 : b }) → cons x._2)
+              )
         }
+
+let example0 =
+        assert
+      :   unzip
+            Text
+            Bool
+            [ { _1 = "ABC", _2 = True }
+            , { _1 = "DEF", _2 = False }
+            , { _1 = "GHI", _2 = True }
+            ]
+        ≡ { _1 = [ "ABC", "DEF", "GHI" ], _2 = [ True, False, True ] }
+
+let example1 =
+        assert
+      :   unzip Text Bool ([] : List { _1 : Text, _2 : Bool })
+        ≡ { _1 = [] : List Text, _2 = [] : List Bool }
 
 in  unzip
diff --git a/dhall-lang/Prelude/Map/Entry b/dhall-lang/Prelude/Map/Entry
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/Map/Entry
@@ -0,0 +1,7 @@
+{- The type of each key-value pair in a `Map`
+-}
+let Entry
+    : Type → Type → Type
+    = λ(k : Type) → λ(v : Type) → { mapKey : k, mapValue : v }
+
+in  Entry
diff --git a/dhall-lang/Prelude/Map/Type b/dhall-lang/Prelude/Map/Type
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/Map/Type
@@ -0,0 +1,24 @@
+{- This is the canonical way to encode a dynamic list of key-value pairs.
+
+   Tools (such as `dhall-to-json`/`dhall-to-yaml` will recognize values of this
+   type and convert them to maps/dictionaries/hashes in the target language
+
+   For example, `dhall-to-json` converts a Dhall value like this:
+
+   ```
+   [ { mapKey = "foo", mapValue = 1 }
+   , { mapKey = "bar", mapValue = 2 }
+   ] : ./Map Text Natural
+   ```
+
+   ... to a JSON value like this:
+
+   ```
+   { "foo": 1, "bar", 2 }
+   ```
+-}
+let Map
+    : Type → Type → Type
+    = λ(k : Type) → λ(v : Type) → List { mapKey : k, mapValue : v }
+
+in  Map
diff --git a/dhall-lang/Prelude/Map/keys b/dhall-lang/Prelude/Map/keys
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/Map/keys
@@ -0,0 +1,38 @@
+{-
+Get all of the keys of a `Map` as a `List`
+-}
+let Map =
+        ./Type sha256:210c7a9eba71efbb0f7a66b3dcf8b9d3976ffc2bc0e907aadfb6aa29c333e8ed
+      ? ./Type
+
+let Entry =
+        ./Entry sha256:f334283bdd9cd88e6ea510ca914bc221fc2dab5fb424d24514b2e0df600d5346
+      ? ./Entry
+
+let List/map =
+        ../List/map sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680
+      ? ../List/map
+
+let keys
+    : ∀(k : Type) → ∀(v : Type) → Map k v → List k
+    =   λ(k : Type)
+      → λ(v : Type)
+      → List/map (Entry k v) k (λ(x : Entry k v) → x.mapKey)
+
+let example0 =
+        assert
+      :   keys
+            Text
+            Natural
+            [ { mapKey = "A", mapValue = 2 }
+            , { mapKey = "B", mapValue = 3 }
+            , { mapKey = "C", mapValue = 5 }
+            ]
+        ≡ [ "A", "B", "C" ]
+
+let example1 =
+        assert
+      :   keys Text Natural ([] : List { mapKey : Text, mapValue : Natural })
+        ≡ ([] : List Text)
+
+in  keys
diff --git a/dhall-lang/Prelude/Map/map b/dhall-lang/Prelude/Map/map
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/Map/map
@@ -0,0 +1,57 @@
+{-
+Transform a `Map` by applying a function to each value
+-}
+let Map =
+        ./Type sha256:210c7a9eba71efbb0f7a66b3dcf8b9d3976ffc2bc0e907aadfb6aa29c333e8ed
+      ? ./Type
+
+let Entry =
+        ./Entry sha256:f334283bdd9cd88e6ea510ca914bc221fc2dab5fb424d24514b2e0df600d5346
+      ? ./Entry
+
+let List/map =
+        ../List/map sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680
+      ? ../List/map
+
+let map
+    : ∀(k : Type) → ∀(a : Type) → ∀(b : Type) → (a → b) → Map k a → Map k b
+    =   λ(k : Type)
+      → λ(a : Type)
+      → λ(b : Type)
+      → λ(f : a → b)
+      → λ(m : Map k a)
+      → List/map
+          (Entry k a)
+          (Entry k b)
+          (   λ(before : Entry k a)
+            → { mapKey = before.mapKey, mapValue = f before.mapValue }
+          )
+          m
+
+let example0 =
+        assert
+      :   map
+            Text
+            Natural
+            Bool
+            Natural/even
+            [ { mapKey = "A", mapValue = 2 }
+            , { mapKey = "B", mapValue = 3 }
+            , { mapKey = "C", mapValue = 5 }
+            ]
+        ≡ [ { mapKey = "A", mapValue = True }
+          , { mapKey = "B", mapValue = False }
+          , { mapKey = "C", mapValue = False }
+          ]
+
+let example1 =
+        assert
+      :   map
+            Text
+            Natural
+            Bool
+            Natural/even
+            ([] : List { mapKey : Text, mapValue : Natural })
+        ≡ ([] : List { mapKey : Text, mapValue : Bool })
+
+in  map
diff --git a/dhall-lang/Prelude/Map/package.dhall b/dhall-lang/Prelude/Map/package.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/Map/package.dhall
@@ -0,0 +1,10 @@
+{ keys =
+      ./keys sha256:d13ec34e6acf7c349d82272ef09a37c7bdf37f0dab489e9df47a1ff215d9f5e7
+    ? ./keys
+, map =
+      ./map sha256:23e09b0b9f08649797dfe1ca39755d5e1c7cad2d0944bdd36c7a0bf804bde8d0
+    ? ./map
+, values =
+      ./values sha256:ae02cfb06a9307cbecc06130e84fd0c7b96b7f1f11648961e1b030ec00940be8
+    ? ./values
+}
diff --git a/dhall-lang/Prelude/Map/values b/dhall-lang/Prelude/Map/values
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/Map/values
@@ -0,0 +1,38 @@
+{-
+Get all of the values of a `Map` as a `List`
+-}
+let Map =
+        ./Type sha256:210c7a9eba71efbb0f7a66b3dcf8b9d3976ffc2bc0e907aadfb6aa29c333e8ed
+      ? ./Type
+
+let Entry =
+        ./Entry sha256:f334283bdd9cd88e6ea510ca914bc221fc2dab5fb424d24514b2e0df600d5346
+      ? ./Entry
+
+let List/map =
+        ../List/map sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680
+      ? ../List/map
+
+let values
+    : ∀(k : Type) → ∀(v : Type) → Map k v → List v
+    =   λ(k : Type)
+      → λ(v : Type)
+      → List/map (Entry k v) v (λ(x : Entry k v) → x.mapValue)
+
+let example0 =
+        assert
+      :   values
+            Text
+            Natural
+            [ { mapKey = "A", mapValue = 2 }
+            , { mapKey = "B", mapValue = 3 }
+            , { mapKey = "C", mapValue = 5 }
+            ]
+        ≡ [ 2, 3, 5 ]
+
+let example1 =
+        assert
+      :   values Text Natural ([] : List { mapKey : Text, mapValue : Natural })
+        ≡ ([] : List Natural)
+
+in  values
diff --git a/dhall-lang/Prelude/Natural/build b/dhall-lang/Prelude/Natural/build
--- a/dhall-lang/Prelude/Natural/build
+++ b/dhall-lang/Prelude/Natural/build
@@ -1,25 +1,5 @@
 {-
 `build` is the inverse of `fold`
-
-Examples:
-
-```
-./build
-(   λ(natural : Type)
-→   λ(succ : natural → natural)
-→   λ(zero : natural)
-→   succ (succ (succ zero))
-)
-= 3
-
-./build
-(   λ(natural : Type)
-→   λ(succ : natural → natural)
-→   λ(zero : natural)
-→   zero
-)
-= 0
-```
 -}
 let build
     :   (   ∀(natural : Type)
@@ -29,5 +9,25 @@
         )
       → Natural
     = Natural/build
+
+let example0 =
+        assert
+      :   build
+            (   λ(natural : Type)
+              → λ(succ : natural → natural)
+              → λ(zero : natural)
+              → succ (succ (succ zero))
+            )
+        ≡ 3
+
+let example1 =
+        assert
+      :   build
+            (   λ(natural : Type)
+              → λ(succ : natural → natural)
+              → λ(zero : natural)
+              → zero
+            )
+        ≡ 0
 
 in  build
diff --git a/dhall-lang/Prelude/Natural/enumerate b/dhall-lang/Prelude/Natural/enumerate
--- a/dhall-lang/Prelude/Natural/enumerate
+++ b/dhall-lang/Prelude/Natural/enumerate
@@ -1,36 +1,32 @@
 {-
 Generate a list of numbers from `0` up to but not including the specified
 number
-
-Examples:
-
-```
-./enumerate 10 = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
-
-./enumerate 0 = [] : List Natural
-```
 -}
 let enumerate
     : Natural → List Natural
     =   λ(n : Natural)
       → List/build
-        Natural
-        (   λ(list : Type)
-          → λ(cons : Natural → list → list)
-          → List/fold
-            { index : Natural, value : {} }
-            ( List/indexed
-              {}
-              ( List/build
-                {}
-                (   λ(list : Type)
-                  → λ(cons : {} → list → list)
-                  → Natural/fold n list (cons {=})
+          Natural
+          (   λ(list : Type)
+            → λ(cons : Natural → list → list)
+            → List/fold
+                { index : Natural, value : {} }
+                ( List/indexed
+                    {}
+                    ( List/build
+                        {}
+                        (   λ(list : Type)
+                          → λ(cons : {} → list → list)
+                          → Natural/fold n list (cons {=})
+                        )
+                    )
                 )
-              )
-            )
-            list
-            (λ(x : { index : Natural, value : {} }) → cons x.index)
-        )
+                list
+                (λ(x : { index : Natural, value : {} }) → cons x.index)
+          )
+
+let example0 = assert : enumerate 10 ≡ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
+
+let example1 = assert : enumerate 0 ≡ ([] : List Natural)
 
 in  enumerate
diff --git a/dhall-lang/Prelude/Natural/equal b/dhall-lang/Prelude/Natural/equal
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/Natural/equal
@@ -0,0 +1,15 @@
+{-
+`equal` checks if two Naturals are equal.
+-}
+let equal
+    : Natural → Natural → Bool
+    =   λ(a : Natural)
+      → λ(b : Natural)
+      →     Natural/isZero (Natural/subtract a b)
+        &&  Natural/isZero (Natural/subtract b a)
+
+let example0 = assert : equal 5 5 ≡ True
+
+let example1 = assert : equal 5 6 ≡ False
+
+in  equal
diff --git a/dhall-lang/Prelude/Natural/even b/dhall-lang/Prelude/Natural/even
--- a/dhall-lang/Prelude/Natural/even
+++ b/dhall-lang/Prelude/Natural/even
@@ -1,12 +1,10 @@
 {-
 Returns `True` if a number if even and returns `False` otherwise
+-}
+let even : Natural → Bool = Natural/even
 
-Examples:
+let example0 = assert : even 3 ≡ False
 
-```
-./even 3 = False
+let example1 = assert : even 0 ≡ True
 
-./even 0 = True
-```
--}
-let even : Natural → Bool = Natural/even in even
+in  even
diff --git a/dhall-lang/Prelude/Natural/fold b/dhall-lang/Prelude/Natural/fold
--- a/dhall-lang/Prelude/Natural/fold
+++ b/dhall-lang/Prelude/Natural/fold
@@ -3,24 +3,6 @@
 
 If you treat the number `3` as `succ (succ (succ zero))` then a `fold` just
 replaces each `succ` and `zero` with something else
-
-Examples:
-
-```
-./fold 3 Natural (λ(x : Natural) → 5 * x) 1 = 125
-
-λ(zero : Natural) → ./fold 3 Natural (λ(x : Natural) → 5 * x) zero
-= λ(zero : Natural) → 5 * (5 * (5 * zero))
-
-    λ(natural : Type)
-→   λ(succ : natural → natural)
-→   λ(zero : natural)
-→   ./fold 3 natural succ zero
-=   λ(natural : Type)
-→   λ(succ : natural → natural)
-→   λ(zero : natural)
-→   succ (succ (succ zero))
-```
 -}
 let fold
     :   Natural
@@ -29,5 +11,25 @@
       → ∀(zero : natural)
       → natural
     = Natural/fold
+
+let example0 = assert : fold 3 Natural (λ(x : Natural) → 5 * x) 1 ≡ 125
+
+let example1 =
+        assert
+      :   (λ(zero : Natural) → fold 3 Natural (λ(x : Natural) → 5 * x) zero)
+        ≡ (λ(zero : Natural) → 5 * (5 * (5 * zero)))
+
+let example2 =
+        assert
+      :   (   λ(natural : Type)
+            → λ(succ : natural → natural)
+            → λ(zero : natural)
+            → fold 3 natural succ zero
+          )
+        ≡ (   λ(natural : Type)
+            → λ(succ : natural → natural)
+            → λ(zero : natural)
+            → succ (succ (succ zero))
+          )
 
 in  fold
diff --git a/dhall-lang/Prelude/Natural/greaterThan b/dhall-lang/Prelude/Natural/greaterThan
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/Natural/greaterThan
@@ -0,0 +1,23 @@
+{-
+`greaterThan` checks if one Natural is strictly greater than another.
+-}
+
+let Bool/not =
+        ../Bool/not sha256:723df402df24377d8a853afed08d9d69a0a6d86e2e5b2bac8960b0d4756c7dc4
+      ? ../Bool/not
+
+let lessThanEqual =
+        ./lessThanEqual sha256:1a5caa2b80a42b9f58fff58e47ac0d9a9946d0b2d36c54034b8ddfe3cb0f3c99
+      ? ./lessThanEqual
+
+let greaterThan
+    : Natural → Natural → Bool
+    = λ(x : Natural) → λ(y : Natural) → Bool/not (lessThanEqual x y)
+
+let example0 = assert : greaterThan 5 6 ≡ False
+
+let example1 = assert : greaterThan 5 5 ≡ False
+
+let example2 = assert : greaterThan 5 4 ≡ True
+
+in  greaterThan
diff --git a/dhall-lang/Prelude/Natural/greaterThanEqual b/dhall-lang/Prelude/Natural/greaterThanEqual
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/Natural/greaterThanEqual
@@ -0,0 +1,22 @@
+{-
+`greaterThanEqual` checks if one Natural is greater than or equal to another.
+-}
+let Bool/not =
+        ../Bool/not sha256:723df402df24377d8a853afed08d9d69a0a6d86e2e5b2bac8960b0d4756c7dc4
+      ? ../Bool/not
+
+let lessThan =
+        ./lessThan sha256:d8a37951fd3f88dcc3927c20b73e6c53499f5275d949eed59bb77ea748492bf0
+      ? ./lessThan
+
+let greaterThanEqual
+    : Natural → Natural → Bool
+    = λ(x : Natural) → λ(y : Natural) → Bool/not (lessThan x y)
+
+let example0 = assert : greaterThanEqual 5 6 ≡ False
+
+let example1 = assert : greaterThanEqual 5 5 ≡ True
+
+let example1 = assert : greaterThanEqual 5 4 ≡ True
+
+in  greaterThanEqual
diff --git a/dhall-lang/Prelude/Natural/isZero b/dhall-lang/Prelude/Natural/isZero
--- a/dhall-lang/Prelude/Natural/isZero
+++ b/dhall-lang/Prelude/Natural/isZero
@@ -1,12 +1,10 @@
 {-
 Returns `True` if a number is `0` and returns `False` otherwise
+-}
+let isZero : Natural → Bool = Natural/isZero
 
-Examples:
+let example0 = assert : isZero 2 ≡ False
 
-```
-./isZero 2 = False
+let example1 = assert : isZero 0 ≡ True
 
-./isZero 0 = True
-```
--}
-let isZero : Natural → Bool = Natural/isZero in isZero
+in  isZero
diff --git a/dhall-lang/Prelude/Natural/lessThan b/dhall-lang/Prelude/Natural/lessThan
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/Natural/lessThan
@@ -0,0 +1,23 @@
+{-
+`lessThan` checks if one Natural is strictly less than another.
+
+Examples:
+
+```
+```
+-}
+let lessThanEqual =
+        ./lessThanEqual sha256:1a5caa2b80a42b9f58fff58e47ac0d9a9946d0b2d36c54034b8ddfe3cb0f3c99
+      ? ./lessThanEqual
+
+let lessThan
+    : Natural → Natural → Bool
+    = λ(x : Natural) → λ(y : Natural) → lessThanEqual (x + 1) y
+
+let example0 = assert : lessThan 5 6 ≡ True
+
+let example1 = assert : lessThan 5 5 ≡ False
+
+let example2 = assert : lessThan 5 4 ≡ False
+
+in  lessThan
diff --git a/dhall-lang/Prelude/Natural/lessThanEqual b/dhall-lang/Prelude/Natural/lessThanEqual
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/Natural/lessThanEqual
@@ -0,0 +1,15 @@
+
+{-
+`lessThanEqual` checks if one Natural is less than or equal to another.
+-}
+let lessThanEqual
+    : Natural → Natural → Bool
+    = λ(x : Natural) → λ(y : Natural) → Natural/isZero (Natural/subtract y x)
+
+let example0 = assert : lessThanEqual 5 6 ≡ True
+
+let example1 = assert : lessThanEqual 5 5 ≡ True
+
+let example2 = assert : lessThanEqual 5 4 ≡ False
+
+in  lessThanEqual
diff --git a/dhall-lang/Prelude/Natural/odd b/dhall-lang/Prelude/Natural/odd
--- a/dhall-lang/Prelude/Natural/odd
+++ b/dhall-lang/Prelude/Natural/odd
@@ -1,12 +1,10 @@
 {-
 Returns `True` if a number is odd and returns `False` otherwise
+-}
+let odd : Natural → Bool = Natural/odd
 
-Examples:
+let example0 = assert : odd 3 ≡ True
 
-```
-./odd 3 = True
+let example1 = assert : odd 0 ≡ False
 
-./odd 0 = False
-```
--}
-let odd : Natural → Bool = Natural/odd in odd
+in  odd
diff --git a/dhall-lang/Prelude/Natural/package.dhall b/dhall-lang/Prelude/Natural/package.dhall
--- a/dhall-lang/Prelude/Natural/package.dhall
+++ b/dhall-lang/Prelude/Natural/package.dhall
@@ -31,4 +31,19 @@
 , toInteger =
       ./toInteger sha256:160d2d278619f3da34a1f4f02e739a447e4f2aa5a2978c45b710515b41491e1f
     ? ./toInteger
+, lessThan =
+      ./lessThan sha256:d8a37951fd3f88dcc3927c20b73e6c53499f5275d949eed59bb77ea748492bf0
+    ? ./lessThan
+, lessThanEqual =
+      ./lessThanEqual sha256:1a5caa2b80a42b9f58fff58e47ac0d9a9946d0b2d36c54034b8ddfe3cb0f3c99
+    ? ./lessThanEqual
+, equal =
+      ./equal sha256:9e0e952e097a2a974ca4ed3e65bcf395cda2bb54382c8ecc3963bca50bfff124
+    ? ./equal
+, greaterThanEqual =
+      ./greaterThanEqual sha256:8665ab478524416ecca7573488eb9b64c12a39f1ea86353b67735cf4d3a3bc4f
+    ? ./greaterThanEqual
+, greaterThan =
+      ./greaterThan sha256:f702abcdfcd7ad73619b9285d7e41c3a1d017fb6b8d037cf40bd93bf30c09b2c
+    ? ./greaterThan
 }
diff --git a/dhall-lang/Prelude/Natural/product b/dhall-lang/Prelude/Natural/product
--- a/dhall-lang/Prelude/Natural/product
+++ b/dhall-lang/Prelude/Natural/product
@@ -1,17 +1,13 @@
 {-
 Multiply all the numbers in a `List`
-
-Examples:
-
-```
-./product [ 2, 3, 5 ] = 30
-
-./product ([] : List Natural) = 1
-```
 -}
 let product
     : List Natural → Natural
     =   λ(xs : List Natural)
       → List/fold Natural xs Natural (λ(l : Natural) → λ(r : Natural) → l * r) 1
+
+let example0 = assert : product [ 2, 3, 5 ] ≡ 30
+
+let example1 = assert : product ([] : List Natural) ≡ 1
 
 in  product
diff --git a/dhall-lang/Prelude/Natural/show b/dhall-lang/Prelude/Natural/show
--- a/dhall-lang/Prelude/Natural/show
+++ b/dhall-lang/Prelude/Natural/show
@@ -1,13 +1,11 @@
 {-
 Render a `Natural` number as `Text` using the same representation as Dhall
 source code (i.e. a decimal number)
+-}
+let show : Natural → Text = Natural/show
 
-Examples:
+let example0 = assert : show 3 ≡ "3"
 
-```
-./show 3 = "3"
+let example1 = assert : show 0 ≡ "0"
 
-./show 0 = "0"
-```
--}
-let show : Natural → Text = Natural/show in show
+in  show
diff --git a/dhall-lang/Prelude/Natural/sum b/dhall-lang/Prelude/Natural/sum
--- a/dhall-lang/Prelude/Natural/sum
+++ b/dhall-lang/Prelude/Natural/sum
@@ -1,17 +1,13 @@
 {-
 Add all the numbers in a `List`
-
-Examples:
-
-```
-./sum [ 2, 3, 5 ] = 10
-
-./sum ([] : List Natural) = 0
-```
 -}
 let sum
     : List Natural → Natural
     =   λ(xs : List Natural)
       → List/fold Natural xs Natural (λ(l : Natural) → λ(r : Natural) → l + r) 0
+
+let example = assert : sum [ 2, 3, 5 ] ≡ 10
+
+let example = assert : sum ([] : List Natural) ≡ 0
 
 in  sum
diff --git a/dhall-lang/Prelude/Natural/toDouble b/dhall-lang/Prelude/Natural/toDouble
--- a/dhall-lang/Prelude/Natural/toDouble
+++ b/dhall-lang/Prelude/Natural/toDouble
@@ -1,16 +1,12 @@
 {-
 Convert a `Natural` number to the corresponding `Double`
-
-Examples:
-
-```
-./toDouble 3 = 3.0
-
-./toDouble 0 = 0.0
-```
 -}
 let toDouble
     : Natural → Double
     = λ(n : Natural) → Integer/toDouble (Natural/toInteger n)
+
+let example0 = assert : toDouble 3 ≡ 3.0
+
+let example1 = assert : toDouble 0 ≡ 0.0
 
 in  toDouble
diff --git a/dhall-lang/Prelude/Natural/toInteger b/dhall-lang/Prelude/Natural/toInteger
--- a/dhall-lang/Prelude/Natural/toInteger
+++ b/dhall-lang/Prelude/Natural/toInteger
@@ -1,12 +1,10 @@
 {-
 Convert a `Natural` number to the corresponding `Integer`
+-}
+let toInteger : Natural → Integer = Natural/toInteger
 
-Examples:
+let example0 = assert : toInteger 3 ≡ +3
 
-```
-./toInteger 3 = +3
+let example1 = assert : toInteger 0 ≡ +0
 
-./toInteger 0 = +0
-```
--}
-let toInteger : Natural → Integer = Natural/toInteger in toInteger
+in  toInteger
diff --git a/dhall-lang/Prelude/Optional/all b/dhall-lang/Prelude/Optional/all
--- a/dhall-lang/Prelude/Optional/all
+++ b/dhall-lang/Prelude/Optional/all
@@ -1,14 +1,6 @@
 {-
 Returns `False` if the supplied function returns `False` for a present element
 and `True` otherwise:
-
-Examples:
-
-```
-./all Natural Natural/even (Some 3) = False
-
-./all Natural Natural/even (None Natural) = True
-```
 -}
 let all
     : ∀(a : Type) → (a → Bool) → Optional a → Bool
@@ -16,5 +8,9 @@
       → λ(f : a → Bool)
       → λ(xs : Optional a)
       → Optional/fold a xs Bool f True
+
+let example0 = assert : all Natural Natural/even (Some 3) ≡ False
+
+let example1 = assert : all Natural Natural/even (None Natural) ≡ True
 
 in  all
diff --git a/dhall-lang/Prelude/Optional/any b/dhall-lang/Prelude/Optional/any
--- a/dhall-lang/Prelude/Optional/any
+++ b/dhall-lang/Prelude/Optional/any
@@ -1,14 +1,6 @@
 {-
 Returns `True` if the supplied function returns `True` for a present element and
 `False` otherwise
-
-Examples:
-
-```
-./any Natural Natural/even (Some 2) = True
-
-./any Natural Natural/even (None Natural) = False
-```
 -}
 let any
     : ∀(a : Type) → (a → Bool) → Optional a → Bool
@@ -16,5 +8,9 @@
       → λ(f : a → Bool)
       → λ(xs : Optional a)
       → Optional/fold a xs Bool f False
+
+let example0 = assert : any Natural Natural/even (Some 2) ≡ True
+
+let example1 = assert : any Natural Natural/even (None Natural) ≡ False
 
 in  any
diff --git a/dhall-lang/Prelude/Optional/build b/dhall-lang/Prelude/Optional/build
--- a/dhall-lang/Prelude/Optional/build
+++ b/dhall-lang/Prelude/Optional/build
@@ -1,27 +1,5 @@
 {-
 `build` is the inverse of `fold`
-
-Examples:
-
-```
-./build
-Natural
-(   λ(optional : Type)
-→   λ(some : Natural → optional)
-→   λ(none : optional)
-→   some 1
-)
-= Some 1
-
-./build
-Natural
-(   λ(optional : Type)
-→   λ(some : Natural → optional)
-→   λ(none : optional)
-→   none
-)
-= None Natural
-```
 -}
 let build
     :   ∀(a : Type)
@@ -32,5 +10,27 @@
         )
       → Optional a
     = Optional/build
+
+let example0 =
+        assert
+      :   build
+            Natural
+            (   λ(optional : Type)
+              → λ(some : Natural → optional)
+              → λ(none : optional)
+              → some 1
+            )
+        ≡ Some 1
+
+let example1 =
+        assert
+      :   build
+            Natural
+            (   λ(optional : Type)
+              → λ(some : Natural → optional)
+              → λ(none : optional)
+              → none
+            )
+        ≡ None Natural
 
 in  build
diff --git a/dhall-lang/Prelude/Optional/concat b/dhall-lang/Prelude/Optional/concat
--- a/dhall-lang/Prelude/Optional/concat
+++ b/dhall-lang/Prelude/Optional/concat
@@ -1,28 +1,21 @@
 {-
 Flatten two `Optional` layers into a single `Optional` layer
-
-Examples:
-
-```
-./concat Natural (Some (Some 1))
-= Some 1
-
-./concat Natural (Some (None Natural))
-= None Natural
-
-./concat Natural (None (Optional Natural))
-= None Natural
-```
 -}
 let concat
     : ∀(a : Type) → Optional (Optional a) → Optional a
     =   λ(a : Type)
       → λ(x : Optional (Optional a))
       → Optional/fold
-        (Optional a)
-        x
-        (Optional a)
-        (λ(y : Optional a) → y)
-        (None a)
+          (Optional a)
+          x
+          (Optional a)
+          (λ(y : Optional a) → y)
+          (None a)
+
+let example0 = assert : concat Natural (Some (Some 1)) ≡ Some 1
+
+let example1 = assert : concat Natural (Some (None Natural)) ≡ None Natural
+
+let example2 = assert : concat Natural (None (Optional Natural)) ≡ None Natural
 
 in  concat
diff --git a/dhall-lang/Prelude/Optional/filter b/dhall-lang/Prelude/Optional/filter
--- a/dhall-lang/Prelude/Optional/filter
+++ b/dhall-lang/Prelude/Optional/filter
@@ -1,15 +1,5 @@
 {-
 Only keep an `Optional` element if the supplied function returns `True`
-
-Examples:
-
-```
-./filter Natural Natural/even (Some 2)
-= Some 2
-
-./filter Natural Natural/odd (Some 2)
-= None Natural
-```
 -}
 let filter
     : ∀(a : Type) → (a → Bool) → Optional a → Optional a
@@ -17,16 +7,20 @@
       → λ(f : a → Bool)
       → λ(xs : Optional a)
       → Optional/build
-        a
-        (   λ(optional : Type)
-          → λ(some : a → optional)
-          → λ(none : optional)
-          → Optional/fold
-            a
-            xs
-            optional
-            (λ(x : a) → if f x then some x else none)
-            none
-        )
+          a
+          (   λ(optional : Type)
+            → λ(some : a → optional)
+            → λ(none : optional)
+            → Optional/fold
+                a
+                xs
+                optional
+                (λ(x : a) → if f x then some x else none)
+                none
+          )
+
+let example0 = assert : filter Natural Natural/even (Some 2) ≡ Some 2
+
+let example1 = assert : filter Natural Natural/odd (Some 2) ≡ None Natural
 
 in  filter
diff --git a/dhall-lang/Prelude/Optional/fold b/dhall-lang/Prelude/Optional/fold
--- a/dhall-lang/Prelude/Optional/fold
+++ b/dhall-lang/Prelude/Optional/fold
@@ -1,13 +1,5 @@
 {-
 `fold` is the primitive function for consuming `Optional` values
-
-Examples:
-
-```
-./fold Natural (Some 2) Natural (λ(x : Natural) → x) 0 = 2
-
-./fold Natural (None Natural) Natural (λ(x : Natural) → x) 0 = 0
-```
 -}
 let fold
     :   ∀(a : Type)
@@ -17,5 +9,10 @@
       → ∀(none : optional)
       → optional
     = Optional/fold
+
+let example0 = assert : fold Natural (Some 2) Natural (λ(x : Natural) → x) 0 ≡ 2
+
+let example1 =
+      assert : fold Natural (None Natural) Natural (λ(x : Natural) → x) 0 ≡ 0
 
 in  fold
diff --git a/dhall-lang/Prelude/Optional/head b/dhall-lang/Prelude/Optional/head
--- a/dhall-lang/Prelude/Optional/head
+++ b/dhall-lang/Prelude/Optional/head
@@ -1,28 +1,26 @@
 {-
 Returns the first non-empty `Optional` value in a `List`
-
-Examples:
-
-```
-./head Natural [ None Natural, Some 1, Some 2 ] = Some 1
-
-./head Natural [ None Natural, None Natural ] = None Natural
-
-./head Natural ([] : List (Optional Natural)) = None Natural
-```
 -}
 let head
     : ∀(a : Type) → List (Optional a) → Optional a
     =   λ(a : Type)
       → λ(xs : List (Optional a))
       → List/fold
-        (Optional a)
-        xs
-        (Optional a)
-        (   λ(l : Optional a)
-          → λ(r : Optional a)
-          → Optional/fold a l (Optional a) (λ(x : a) → Some x) r
-        )
-        (None a)
+          (Optional a)
+          xs
+          (Optional a)
+          (   λ(l : Optional a)
+            → λ(r : Optional a)
+            → Optional/fold a l (Optional a) (λ(x : a) → Some x) r
+          )
+          (None a)
+
+let example0 = assert : head Natural [ None Natural, Some 1, Some 2 ] ≡ Some 1
+
+let example1 =
+      assert : head Natural [ None Natural, None Natural ] ≡ None Natural
+
+let example2 =
+      assert : head Natural ([] : List (Optional Natural)) ≡ None Natural
 
 in  head
diff --git a/dhall-lang/Prelude/Optional/last b/dhall-lang/Prelude/Optional/last
--- a/dhall-lang/Prelude/Optional/last
+++ b/dhall-lang/Prelude/Optional/last
@@ -1,28 +1,26 @@
 {-
 Returns the last non-empty `Optional` value in a `List`
-
-Examples:
-
-```
-./last Natural [ None Natural, Some 1, Some 2 ] = Some 2
-
-./last Natural [ None Natural, None Natural ] = None Natural
-
-./last Natural ([] : List (Optional Natural)) = None Natural
-```
 -}
 let last
     : ∀(a : Type) → List (Optional a) → Optional a
     =   λ(a : Type)
       → λ(xs : List (Optional a))
       → List/fold
-        (Optional a)
-        xs
-        (Optional a)
-        (   λ(l : Optional a)
-          → λ(r : Optional a)
-          → Optional/fold a r (Optional a) (λ(x : a) → Some x) l
-        )
-        (None a)
+          (Optional a)
+          xs
+          (Optional a)
+          (   λ(l : Optional a)
+            → λ(r : Optional a)
+            → Optional/fold a r (Optional a) (λ(x : a) → Some x) l
+          )
+          (None a)
+
+let example0 = assert : last Natural [ None Natural, Some 1, Some 2 ] ≡ Some 2
+
+let example1 =
+      assert : last Natural [ None Natural, None Natural ] ≡ None Natural
+
+let example2 =
+      assert : last Natural ([] : List (Optional Natural)) ≡ None Natural
 
 in  last
diff --git a/dhall-lang/Prelude/Optional/length b/dhall-lang/Prelude/Optional/length
--- a/dhall-lang/Prelude/Optional/length
+++ b/dhall-lang/Prelude/Optional/length
@@ -1,18 +1,14 @@
 {-
 Returns `1` if the `Optional` value is present and `0` if the value is absent
-
-Examples:
-
-```
-./length Natural (Some 2) = 1
-
-./length Natural (None Natural) = 0
-```
 -}
 let length
     : ∀(a : Type) → Optional a → Natural
     =   λ(a : Type)
       → λ(xs : Optional a)
       → Optional/fold a xs Natural (λ(_ : a) → 1) 0
+
+let example0 = assert : length Natural (Some 2) ≡ 1
+
+let example1 = assert : length Natural (None Natural) ≡ 0
 
 in  length
diff --git a/dhall-lang/Prelude/Optional/map b/dhall-lang/Prelude/Optional/map
--- a/dhall-lang/Prelude/Optional/map
+++ b/dhall-lang/Prelude/Optional/map
@@ -1,13 +1,5 @@
 {-
 Transform an `Optional` value with a function
-
-Examples:
-
-```
-./map Natural Bool Natural/even (Some 3) = Some False
-
-./map Natural Bool Natural/even (None Natural) = None Bool
-```
 -}
 let map
     : ∀(a : Type) → ∀(b : Type) → (a → b) → Optional a → Optional b
@@ -16,5 +8,9 @@
       → λ(f : a → b)
       → λ(o : Optional a)
       → Optional/fold a o (Optional b) (λ(x : a) → Some (f x)) (None b)
+
+let example0 = assert : map Natural Bool Natural/even (Some 3) ≡ Some False
+
+let example1 = assert : map Natural Bool Natural/even (None Natural) ≡ None Bool
 
 in  map
diff --git a/dhall-lang/Prelude/Optional/null b/dhall-lang/Prelude/Optional/null
--- a/dhall-lang/Prelude/Optional/null
+++ b/dhall-lang/Prelude/Optional/null
@@ -1,18 +1,14 @@
 {-
 Returns `True` if the `Optional` value is absent and `False` if present
-
-Examples:
-
-```
-./null Natural (Some 2) = False
-
-./null Natural (None Natural) = True
-```
 -}
 let null
     : ∀(a : Type) → Optional a → Bool
     =   λ(a : Type)
       → λ(xs : Optional a)
       → Optional/fold a xs Bool (λ(_ : a) → False) True
+
+let example0 = assert : null Natural (Some 2) ≡ False
+
+let example1 = assert : null Natural (None Natural) ≡ True
 
 in  null
diff --git a/dhall-lang/Prelude/Optional/toList b/dhall-lang/Prelude/Optional/toList
--- a/dhall-lang/Prelude/Optional/toList
+++ b/dhall-lang/Prelude/Optional/toList
@@ -1,18 +1,14 @@
 {-
 Convert an `Optional` value into the equivalent `List`
-
-Examples:
-
-```
-./toList Natural (Some 1) = [ 1 ]
-
-./toList Natural (None Natural) = [] : List Natural
-```
 -}
 let toList
     : ∀(a : Type) → Optional a → List a
     =   λ(a : Type)
       → λ(o : Optional a)
       → Optional/fold a o (List a) (λ(x : a) → [ x ] : List a) ([] : List a)
+
+let example0 = assert : toList Natural (Some 1) ≡ [ 1 ]
+
+let example1 = assert : toList Natural (None Natural) ≡ ([] : List Natural)
 
 in  toList
diff --git a/dhall-lang/Prelude/Optional/unzip b/dhall-lang/Prelude/Optional/unzip
--- a/dhall-lang/Prelude/Optional/unzip
+++ b/dhall-lang/Prelude/Optional/unzip
@@ -1,15 +1,5 @@
 {-
 Unzip an `Optional` value into two separate `Optional` values
-
-Examples:
-
-```
-./unzip Text Bool (Some { _1 = "ABC", _2 = True  })
-= { _1 = Some "ABC", _2 = Some True }
-
-./unzip Text Bool (None { _1 : Text, _2 : Bool })
-= { _1 = None Text, _2 = None Bool }
-```
 -}
 let unzip
     :   ∀(a : Type)
@@ -21,18 +11,28 @@
       → λ(xs : Optional { _1 : a, _2 : b })
       → { _1 =
             Optional/fold
-            { _1 : a, _2 : b }
-            xs
-            (Optional a)
-            (λ(x : { _1 : a, _2 : b }) → Some x._1)
-            (None a)
+              { _1 : a, _2 : b }
+              xs
+              (Optional a)
+              (λ(x : { _1 : a, _2 : b }) → Some x._1)
+              (None a)
         , _2 =
             Optional/fold
-            { _1 : a, _2 : b }
-            xs
-            (Optional b)
-            (λ(x : { _1 : a, _2 : b }) → Some x._2)
-            (None b)
+              { _1 : a, _2 : b }
+              xs
+              (Optional b)
+              (λ(x : { _1 : a, _2 : b }) → Some x._2)
+              (None b)
         }
+
+let example0 =
+        assert
+      :   unzip Text Bool (Some { _1 = "ABC", _2 = True })
+        ≡ { _1 = Some "ABC", _2 = Some True }
+
+let example1 =
+        assert
+      :   unzip Text Bool (None { _1 : Text, _2 : Bool })
+        ≡ { _1 = None Text, _2 = None Bool }
 
 in  unzip
diff --git a/dhall-lang/Prelude/Text/concat b/dhall-lang/Prelude/Text/concat
--- a/dhall-lang/Prelude/Text/concat
+++ b/dhall-lang/Prelude/Text/concat
@@ -1,17 +1,13 @@
 {-
 Concatenate all the `Text` values in a `List`
-
-Examples:
-
-```
-./concat [ "ABC", "DEF", "GHI" ] = "ABCDEFGHI"
-
-./concat ([] : List Text) = ""
-```
 -}
 let concat
     : List Text → Text
     =   λ(xs : List Text)
       → List/fold Text xs Text (λ(x : Text) → λ(y : Text) → x ++ y) ""
+
+let example0 = assert : concat [ "ABC", "DEF", "GHI" ] ≡ "ABCDEFGHI"
+
+let example1 = assert : concat ([] : List Text) ≡ ""
 
 in  concat
diff --git a/dhall-lang/Prelude/Text/concatMap b/dhall-lang/Prelude/Text/concatMap
--- a/dhall-lang/Prelude/Text/concatMap
+++ b/dhall-lang/Prelude/Text/concatMap
@@ -1,15 +1,5 @@
 {-
 Transform each value in a `List` into `Text` and concatenate the result
-
-Examples:
-
-```
-./concatMap Natural (λ(n : Natural) → "${Natural/show n} ") [ 0, 1, 2 ]
-= "0 1 2 "
-
-./concatMap Natural (λ(n : Natural) → "${Natural/show n} ") ([] : List Natural)
-= ""
-```
 -}
 let concatMap
     : ∀(a : Type) → (a → Text) → List a → Text
@@ -17,5 +7,18 @@
       → λ(f : a → Text)
       → λ(xs : List a)
       → List/fold a xs Text (λ(x : a) → λ(y : Text) → f x ++ y) ""
+
+let example0 =
+        assert
+      :   concatMap Natural (λ(n : Natural) → "${Natural/show n} ") [ 0, 1, 2 ]
+        ≡ "0 1 2 "
+
+let example1 =
+        assert
+      :   concatMap
+            Natural
+            (λ(n : Natural) → "${Natural/show n} ")
+            ([] : List Natural)
+        ≡ ""
 
 in  concatMap
diff --git a/dhall-lang/Prelude/Text/concatMapSep b/dhall-lang/Prelude/Text/concatMapSep
--- a/dhall-lang/Prelude/Text/concatMapSep
+++ b/dhall-lang/Prelude/Text/concatMapSep
@@ -1,14 +1,6 @@
 {-
 Transform each value in a `List` to `Text` and then concatenate them with a
 separator in between each value
-
-Examples:
-
-```
-./concatMapSep ", " Natural Natural/show [ 0, 1, 2 ] = "0, 1, 2"
-
-./concatMapSep ", " Natural Natural/show ([] : List Natural) = ""
-```
 -}
 let Status = < Empty | NonEmpty : Text >
 
@@ -20,22 +12,28 @@
       → λ(elements : List a)
       → let status =
               List/fold
-              a
-              elements
-              Status
-              (   λ(x : a)
-                → λ(status : Status)
-                → merge
-                  { Empty =
-                      Status.NonEmpty (f x)
-                  , NonEmpty =
-                        λ(result : Text)
-                      → Status.NonEmpty (f x ++ separator ++ result)
-                  }
-                  status
-              )
-              Status.Empty
+                a
+                elements
+                Status
+                (   λ(x : a)
+                  → λ(status : Status)
+                  → merge
+                      { Empty =
+                          Status.NonEmpty (f x)
+                      , NonEmpty =
+                            λ(result : Text)
+                          → Status.NonEmpty (f x ++ separator ++ result)
+                      }
+                      status
+                )
+                Status.Empty
         
         in  merge { Empty = "", NonEmpty = λ(result : Text) → result } status
+
+let example0 =
+      assert : concatMapSep ", " Natural Natural/show [ 0, 1, 2 ] ≡ "0, 1, 2"
+
+let example1 =
+      assert : concatMapSep ", " Natural Natural/show ([] : List Natural) ≡ ""
 
 in  concatMapSep
diff --git a/dhall-lang/Prelude/Text/concatSep b/dhall-lang/Prelude/Text/concatSep
--- a/dhall-lang/Prelude/Text/concatSep
+++ b/dhall-lang/Prelude/Text/concatSep
@@ -1,13 +1,5 @@
 {-
 Concatenate a `List` of `Text` values with a separator in between each value
-
-Examples:
-
-```
-./concatSep ", " [ "ABC", "DEF", "GHI" ] = "ABC, DEF, GHI"
-
-./concatSep ", " ([] : List Text) = ""
-```
 -}
 let Status = < Empty | NonEmpty : Text >
 
@@ -17,22 +9,26 @@
       → λ(elements : List Text)
       → let status =
               List/fold
-              Text
-              elements
-              Status
-              (   λ(element : Text)
-                → λ(status : Status)
-                → merge
-                  { Empty =
-                      Status.NonEmpty element
-                  , NonEmpty =
-                        λ(result : Text)
-                      → Status.NonEmpty (element ++ separator ++ result)
-                  }
-                  status
-              )
-              Status.Empty
+                Text
+                elements
+                Status
+                (   λ(element : Text)
+                  → λ(status : Status)
+                  → merge
+                      { Empty =
+                          Status.NonEmpty element
+                      , NonEmpty =
+                            λ(result : Text)
+                          → Status.NonEmpty (element ++ separator ++ result)
+                      }
+                      status
+                )
+                Status.Empty
         
         in  merge { Empty = "", NonEmpty = λ(result : Text) → result } status
+
+let example0 = assert : concatSep ", " [ "ABC", "DEF", "GHI" ] ≡ "ABC, DEF, GHI"
+
+let example1 = assert : concatSep ", " ([] : List Text) ≡ ""
 
 in  concatSep
diff --git a/dhall-lang/Prelude/Text/show b/dhall-lang/Prelude/Text/show
--- a/dhall-lang/Prelude/Text/show
+++ b/dhall-lang/Prelude/Text/show
@@ -1,13 +1,12 @@
 {-
 Render a `Text` literal as its own representation as Dhall source code (i.e. a
 double-quoted string literal)
+-}
+let show : Text → Text = Text/show
 
-Examples:
+let example0 = assert : show "ABC" ≡ "\"ABC\""
 
-```
-./show "ABC" = "\"ABC\""
+let example1 =
+      assert : show "\u0000 \$ \\ \n ☺" ≡ "\"\\u0000 \\u0024 \\\\ \\n ☺\""
 
-./show "\u0000 \$ \\ \n \u263a" = "\"\\u0000 \\u0024 \\\\ \\n ☺\""
-```
--}
-let show : Text → Text = Text/show in show
+in  show
diff --git a/dhall-lang/Prelude/XML/Type b/dhall-lang/Prelude/XML/Type
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/XML/Type
@@ -0,0 +1,66 @@
+{- Dhall encoding of an arbitrary XML element
+
+   For example, the following XML element:
+
+```
+<foo n="1"><bar>baz</bar></foo>
+```
+
+   ... corresponds to the following Dhall expression:
+
+
+```
+λ(XML : Type)
+ → λ ( xml
+     : { text :
+           Text → XML
+       , element :
+             { attributes :
+                 List { mapKey : Text, mapValue : Text }
+             , content :
+                 List XML
+             , name :
+                 Text
+             }
+           → XML
+       }
+     )
+ → xml.element
+   { attributes =
+       [ { mapKey = "n", mapValue = "1" } ]
+   , content =
+       [ xml.element
+         { attributes =
+             [] : List { mapKey : Text, mapValue : Text }
+         , content =
+             [ xml.text "baz" ]
+         , name =
+             "bar"
+         }
+       ]
+   , name =
+       "foo"
+   }
+```
+-}
+
+let XML/Type
+    : Type
+    =   ∀(XML : Type)
+      → ∀ ( xml
+          : { text :
+                Text → XML
+            , element :
+                  { attributes :
+                      List { mapKey : Text, mapValue : Text }
+                  , content :
+                      List XML
+                  , name :
+                      Text
+                  }
+                → XML
+            }
+          )
+      → XML
+
+in  XML/Type
diff --git a/dhall-lang/Prelude/XML/attribute b/dhall-lang/Prelude/XML/attribute
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/XML/attribute
@@ -0,0 +1,3 @@
+{- Builds a key-value record with a Text key and value. -}
+
+λ(key : Text) → λ(value : Text) → { mapKey = key, mapValue = value }
diff --git a/dhall-lang/Prelude/XML/element b/dhall-lang/Prelude/XML/element
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/XML/element
@@ -0,0 +1,67 @@
+{- Create an XML element value.
+
+```
+let XML = ./package.dhall
+
+in  XML.render
+    ( XML.element
+      { name = "foo"
+      , attributes = XML.emptyAttributes
+      , content =
+          [ XML.leaf { name = "bar", attributes = [ XML.attribute "n" "1" ] }
+          , XML.leaf { name = "baz", attributes = [ XML.attribute "n" "2" ] }
+          ]
+      }
+    )
+
+= "<foo><bar n=\"1\"/><baz n=\"2\"/></foo>"
+```
+-}
+
+
+let XML =
+        ./Type sha256:461930f3aab769ba537d1a4fd71f411504b0c8d1c1a78d65177be8ded0df8a5c
+      ? ./Type
+
+let List/map =
+        ../List/map sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680
+      ? ../List/map
+
+let Args =
+        { attributes :
+            List { mapKey : Text, mapValue : Text }
+        , name :
+            Text
+        , content :
+            List XML
+        }
+      : Type
+
+let element
+    : Args → XML
+    =   λ(elem : Args)
+      → λ(XML : Type)
+      → λ ( xml
+          : { text :
+                Text → XML
+            , element :
+                  { attributes :
+                      List { mapKey : Text, mapValue : Text }
+                  , content :
+                      List XML
+                  , name :
+                      Text
+                  }
+                → XML
+            }
+          )
+      → xml.element
+          { attributes =
+              elem.attributes
+          , name =
+              elem.name
+          , content =
+              List/map XML@1 XML (λ(x : XML@1) → x XML xml) elem.content
+          }
+
+in  element
diff --git a/dhall-lang/Prelude/XML/emptyAttributes b/dhall-lang/Prelude/XML/emptyAttributes
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/XML/emptyAttributes
@@ -0,0 +1,3 @@
+{- Create an empty XML attribute List. -}
+
+[] : List { mapKey : Text, mapValue : Text }
diff --git a/dhall-lang/Prelude/XML/leaf b/dhall-lang/Prelude/XML/leaf
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/XML/leaf
@@ -0,0 +1,32 @@
+{- Create an XML element value without child elements.
+
+```
+let XML = ./package.dhall
+
+in  XML.render (XML.leaf { name = "foobar", attributes = XML.emptyAttributes })
+
+= "<foobar/>"
+```
+-}
+
+let XML =
+        ./Type sha256:461930f3aab769ba537d1a4fd71f411504b0c8d1c1a78d65177be8ded0df8a5c
+      ? ./Type
+
+let element =
+        ./element sha256:e0b948053c8cd8ccca9c39244d89e3f42db43d222531c18151551dfc75208b4b
+      ? ./element
+
+let leaf
+    :   { attributes : List { mapKey : Text, mapValue : Text }, name : Text }
+      → XML
+    =   λ ( elem
+          : { attributes :
+                List { mapKey : Text, mapValue : Text }
+            , name :
+                Text
+            }
+          )
+      → element (elem ⫽ { content = [] : List XML })
+
+in  leaf
diff --git a/dhall-lang/Prelude/XML/package.dhall b/dhall-lang/Prelude/XML/package.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/XML/package.dhall
@@ -0,0 +1,19 @@
+{ attribute =
+      ./attribute sha256:f7b6c802ca5764d03d5e9a6e48d9cb167c01392f775d9c2c87b83cdaa60ea0cc
+    ? ./attribute
+, render =
+      ./render sha256:8d034f7f97cded14a96147565d489be840e5678480d175b962b2600d85a3230e
+    ? ./render
+, element =
+      ./element sha256:e0b948053c8cd8ccca9c39244d89e3f42db43d222531c18151551dfc75208b4b
+    ? ./element
+, leaf =
+      ./leaf sha256:4383e4fc4bf6a29ac2052776972eb59d5355a1cd067cded80d4ff32840969261
+    ? ./leaf
+, text =
+      ./text sha256:c83cd721d32d7dc28c04ce429c0cb22812639e572637ec348578a58ffb68844f
+    ? ./text
+, emptyAttributes =
+      ./emptyAttributes sha256:11b86e2d3f3c75d47a1d580213d2a03fd2c36d64f3e9b6381de0ba23472f64d5
+    ? ./emptyAttributes
+}
diff --git a/dhall-lang/Prelude/XML/render b/dhall-lang/Prelude/XML/render
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/XML/render
@@ -0,0 +1,70 @@
+{- Render an `XML` value as `Text`
+
+   *WARNING:* rendering does not include any XML injection mitigations,
+   therefore it should not be used to process arbitrary strings into
+   element attributes or element data.
+
+   For indentation and schema validation, see the `xmllint` utility
+   bundled with libxml2.
+
+```
+let XML = ./package.dhall
+
+in  XML.render
+    ( XML.node
+      { name = "foo"
+      , attributes = [ XML.attribute "a" "x", XML.attribute "b" (Natural/show 2) ]
+      , content = [ XML.leaf { name = "bar", attributes = XML.emptyAttributes } ]
+      }
+    )
+= "<foo a=\"x\" b=\"2\"><bar/></foo>"
+```
+
+-}
+
+let XML =
+        ./Type sha256:461930f3aab769ba537d1a4fd71f411504b0c8d1c1a78d65177be8ded0df8a5c
+      ? ./Type
+
+let Text/concatMap =
+        ../Text/concatMap sha256:7a0b0b99643de69d6f94ba49441cd0fa0507cbdfa8ace0295f16097af37e226f
+      ? ../Text/concatMap
+
+let Text/concat =
+        ../Text/concat sha256:731265b0288e8a905ecff95c97333ee2db614c39d69f1514cb8eed9259745fc0
+      ? ../Text/concat
+
+let Attr = { mapKey : Text, mapValue : Text }
+
+let renderAttr = λ(x : Attr) → " ${x.mapKey}=\"${x.mapValue}\""
+
+let render
+    : XML → Text
+    =   λ(x : XML)
+      → x
+          Text
+          { text =
+              λ(d : Text) → d
+          , element =
+                λ ( elem
+                  : { attributes :
+                        List { mapKey : Text, mapValue : Text }
+                    , content :
+                        List Text
+                    , name :
+                        Text
+                    }
+                  )
+              → let attribs = Text/concatMap Attr renderAttr elem.attributes
+                
+                in      "<${elem.name}${attribs}"
+                    ++  (       if Natural/isZero
+                                     (List/length Text elem.content)
+                          
+                          then  "/>"
+                          
+                          else  ">${Text/concat elem.content}</${elem.name}>"
+                        )
+          }
+
+in  render
diff --git a/dhall-lang/Prelude/XML/text b/dhall-lang/Prelude/XML/text
new file mode 100644
--- /dev/null
+++ b/dhall-lang/Prelude/XML/text
@@ -0,0 +1,41 @@
+{- Create a Text value to be inserted into an XML element as content.
+
+```
+let XML = ./package.dhall
+
+in  XML.render
+    ( XML.node
+      { name = "location"
+      , attributes = XML.emptyAttributes
+      , content = [ XML.text "/foo/bar" ]
+      }
+    )
+= "<location>/foo/bar</location>"
+```
+-}
+
+let XML =
+        ./Type sha256:461930f3aab769ba537d1a4fd71f411504b0c8d1c1a78d65177be8ded0df8a5c
+      ? ./Type
+
+let text
+    : Text → XML
+    =   λ(d : Text)
+      → λ(XML : Type)
+      → λ ( xml
+          : { text :
+                Text → XML
+            , element :
+                  { attributes :
+                      List { mapKey : Text, mapValue : Text }
+                  , content :
+                      List XML
+                  , name :
+                      Text
+                  }
+                → XML
+            }
+          )
+      → xml.text d
+
+in  text
diff --git a/dhall-lang/Prelude/package.dhall b/dhall-lang/Prelude/package.dhall
--- a/dhall-lang/Prelude/package.dhall
+++ b/dhall-lang/Prelude/package.dhall
@@ -17,7 +17,7 @@
       ./Map/package.dhall sha256:07cc274220c8bdb2c1a0c2d00d90bc1447e73e0ad2e1d72b89773e923f77e71e
     ? ./Map/package.dhall
 , Natural =
-      ./Natural/package.dhall sha256:fe08155c3a04500df847ca94d013ecd3dfc73ab5c136109b2414fce3ec42b63a
+      ./Natural/package.dhall sha256:8421079b9698b765774455b63f4561f7bfa1506ed3fa39cfb5c34a4cd1c9df4b
     ? ./Natural/package.dhall
 , Optional =
       ./Optional/package.dhall sha256:36a366af67a3c26cd5d196e095d3023f18953c5b5db3a03956fa554609e5442a
@@ -29,6 +29,6 @@
       ./Text/package.dhall sha256:3b6ed813caf2388b91056d625c6b958b72009f85a6af262d4a7b935b18caf62b
     ? ./Text/package.dhall
 , XML =
-      ./XML/package.dhall sha256:abace25be73c3ba823abfba92bb3742a0454d521804a5d19ab5dfbf966473a5d
+      ./XML/package.dhall sha256:6aed7e845c29bc528ced19b99f860c5bcd50f24a1394631fe66f751999f85361
     ? ./XML/package.dhall
 }
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreA.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreA.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreA.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreA.dhall
@@ -1,1 +1,1 @@
-λ(_ : A) → b
+λ(_ : Bool) → _
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreB.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreB.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreB.dhall
@@ -1,1 +1,1 @@
-λ(_ : A) → b
+λ(_ : Bool) → _
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXA.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXA.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXA.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXA.dhall
@@ -1,1 +1,1 @@
-λ(x : A) → x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXB.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXB.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXB.dhall
@@ -1,1 +1,1 @@
-λ(_ : A) → _
+λ(_ : Bool) → _
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXA.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXA.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXA.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXA.dhall
@@ -1,1 +1,1 @@
-λ(x : A) → λ(_ : B) → x
+λ(x : Bool) → λ(_ : Natural) → x
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXB.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXB.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXB.dhall
@@ -1,1 +1,1 @@
-λ(_ : A) → λ(_ : B) → _@1
+λ(_ : Bool) → λ(_ : Natural) → _@1
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXB.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXB.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXB.dhall
@@ -1,1 +1,1 @@
-\(_: Bool) -> \(_: Bool) -> _ && _@1
+λ(_ : Bool) → λ(_ : Bool) → _ && _@1
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXFreeA.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXFreeA.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXFreeA.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXFreeA.dhall
@@ -1,1 +1,4 @@
+{-
+    This test has free variables, so it doesn't typecheck
+-}
 \(x: Bool) -> \(x: Bool) -> [x, x@0, x@1, x@2, x@3]
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXYB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXYB.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXYB.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXYB.dhall
@@ -1,1 +1,1 @@
-\(_: Bool) -> \(_: Bool) -> _@1 && _
+λ(_ : Bool) → λ(_ : Bool) → _@1 && _
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingUnderscoreA.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingUnderscoreA.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingUnderscoreA.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingUnderscoreA.dhall
@@ -1,1 +1,1 @@
-A → B
+Bool → Natural
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingUnderscoreB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingUnderscoreB.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingUnderscoreB.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingUnderscoreB.dhall
@@ -1,1 +1,1 @@
-A → B
+Bool → Natural
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXA.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXA.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXA.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXA.dhall
@@ -1,1 +1,1 @@
-∀(x : A) → x
+∀(x : Type) → x
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXB.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXB.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXB.dhall
@@ -1,1 +1,1 @@
-A → _
+Type → _
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXA.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXA.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXA.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXA.dhall
@@ -1,1 +1,1 @@
-∀(x : A) → B → x
+∀(x : Type) → Type → x
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXB.dhall
--- a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXB.dhall
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXB.dhall
@@ -1,1 +1,1 @@
-A → B → _@1
+Type → Type → _@1
diff --git a/dhall-lang/tests/binary-decode/failure/unit/OperatorUnknownOpcode.dhallb b/dhall-lang/tests/binary-decode/failure/unit/OperatorUnknownOpcode.dhallb
Binary files a/dhall-lang/tests/binary-decode/failure/unit/OperatorUnknownOpcode.dhallb and b/dhall-lang/tests/binary-decode/failure/unit/OperatorUnknownOpcode.dhallb differ
diff --git a/dhall-lang/tests/binary-decode/success/unit/AssertA.dhallb b/dhall-lang/tests/binary-decode/success/unit/AssertA.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/binary-decode/success/unit/AssertA.dhallb differ
diff --git a/dhall-lang/tests/binary-decode/success/unit/AssertB.dhall b/dhall-lang/tests/binary-decode/success/unit/AssertB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/binary-decode/success/unit/AssertB.dhall
@@ -0,0 +1,1 @@
+assert : _
diff --git a/dhall-lang/tests/binary-decode/success/unit/BuiltinNaturalSubtractA.dhallb b/dhall-lang/tests/binary-decode/success/unit/BuiltinNaturalSubtractA.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/binary-decode/success/unit/BuiltinNaturalSubtractA.dhallb
@@ -0,0 +1,1 @@
+pNatural/subtract
diff --git a/dhall-lang/tests/binary-decode/success/unit/BuiltinNaturalSubtractB.dhall b/dhall-lang/tests/binary-decode/success/unit/BuiltinNaturalSubtractB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/binary-decode/success/unit/BuiltinNaturalSubtractB.dhall
@@ -0,0 +1,1 @@
+Natural/subtract
diff --git a/dhall-lang/tests/binary-decode/success/unit/ListEmpty0A.dhallb b/dhall-lang/tests/binary-decode/success/unit/ListEmpty0A.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/binary-decode/success/unit/ListEmpty0A.dhallb
@@ -0,0 +1,1 @@
+gNatural
diff --git a/dhall-lang/tests/binary-decode/success/unit/ListEmpty0B.dhall b/dhall-lang/tests/binary-decode/success/unit/ListEmpty0B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/binary-decode/success/unit/ListEmpty0B.dhall
@@ -0,0 +1,1 @@
+[] : List Natural
diff --git a/dhall-lang/tests/binary-decode/success/unit/ListEmpty1A.dhallb b/dhall-lang/tests/binary-decode/success/unit/ListEmpty1A.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/binary-decode/success/unit/ListEmpty1A.dhallb differ
diff --git a/dhall-lang/tests/binary-decode/success/unit/ListEmpty1B.dhall b/dhall-lang/tests/binary-decode/success/unit/ListEmpty1B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/binary-decode/success/unit/ListEmpty1B.dhall
@@ -0,0 +1,1 @@
+[] : x
diff --git a/dhall-lang/tests/binary-decode/success/unit/ListEmptyA.dhallb b/dhall-lang/tests/binary-decode/success/unit/ListEmptyA.dhallb
deleted file mode 100644
--- a/dhall-lang/tests/binary-decode/success/unit/ListEmptyA.dhallb
+++ /dev/null
@@ -1,1 +0,0 @@
-gNatural
diff --git a/dhall-lang/tests/binary-decode/success/unit/ListEmptyB.dhall b/dhall-lang/tests/binary-decode/success/unit/ListEmptyB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/binary-decode/success/unit/ListEmptyB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[] : List Natural
diff --git a/dhall-lang/tests/binary-decode/success/unit/OperatorEquivA.dhallb b/dhall-lang/tests/binary-decode/success/unit/OperatorEquivA.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/binary-decode/success/unit/OperatorEquivA.dhallb differ
diff --git a/dhall-lang/tests/binary-decode/success/unit/OperatorEquivB.dhall b/dhall-lang/tests/binary-decode/success/unit/OperatorEquivB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/binary-decode/success/unit/OperatorEquivB.dhall
@@ -0,0 +1,1 @@
+_ ≡ _@1
diff --git a/dhall-lang/tests/binary-decode/success/unit/ToMapA.dhallb b/dhall-lang/tests/binary-decode/success/unit/ToMapA.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/binary-decode/success/unit/ToMapA.dhallb differ
diff --git a/dhall-lang/tests/binary-decode/success/unit/ToMapAnnotatedA.dhallb b/dhall-lang/tests/binary-decode/success/unit/ToMapAnnotatedA.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/binary-decode/success/unit/ToMapAnnotatedA.dhallb differ
diff --git a/dhall-lang/tests/binary-decode/success/unit/ToMapAnnotatedB.dhall b/dhall-lang/tests/binary-decode/success/unit/ToMapAnnotatedB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/binary-decode/success/unit/ToMapAnnotatedB.dhall
@@ -0,0 +1,1 @@
+toMap e : T
diff --git a/dhall-lang/tests/binary-decode/success/unit/ToMapB.dhall b/dhall-lang/tests/binary-decode/success/unit/ToMapB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/binary-decode/success/unit/ToMapB.dhall
@@ -0,0 +1,1 @@
+toMap e
diff --git a/dhall-lang/tests/import/data/doesNotTypecheck.dhall b/dhall-lang/tests/import/data/doesNotTypecheck.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/import/data/doesNotTypecheck.dhall
@@ -0,0 +1,1 @@
+0 0
diff --git a/dhall-lang/tests/import/data/nested.dhall b/dhall-lang/tests/import/data/nested.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/import/data/nested.dhall
@@ -0,0 +1,1 @@
+{ x = ./simple.dhall sha256:15f52ecf91c94c1baac02d5a4964b2ed8fa401641a2c8a95e8306ec7c1e3b8d2 }
diff --git a/dhall-lang/tests/import/success/alternativeTypeErrorA.dhall b/dhall-lang/tests/import/success/alternativeTypeErrorA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/import/success/alternativeTypeErrorA.dhall
@@ -0,0 +1,1 @@
+../data/doesNotTypecheck.dhall ? 42
diff --git a/dhall-lang/tests/import/success/alternativeTypeErrorB.dhall b/dhall-lang/tests/import/success/alternativeTypeErrorB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/import/success/alternativeTypeErrorB.dhall
@@ -0,0 +1,1 @@
+42
diff --git a/dhall-lang/tests/import/success/asLocationB.dhall b/dhall-lang/tests/import/success/asLocationB.dhall
--- a/dhall-lang/tests/import/success/asLocationB.dhall
+++ b/dhall-lang/tests/import/success/asLocationB.dhall
@@ -1,8 +1,20 @@
-{ _1 = < Local : Text | Remote : Text | Environment : Text | Missing >.Local "./some/import.dhall"
-, _2 = < Local : Text | Remote : Text | Environment : Text | Missing >.Local "../data/simple.dhall"
-, _3 = < Local : Text | Remote : Text | Environment : Text | Missing >.Local "/absolute/import"
-, _4 = < Local : Text | Remote : Text | Environment : Text | Missing >.Remote "https://prelude.dhall-lang.org/package.dhall"
-, _5 = < Local : Text | Remote : Text | Environment : Text | Missing >.Environment "env:HOME"
-, _6 = < Local : Text | Remote : Text | Environment : Text | Missing >.Missing
-, _7 = < Local : Text | Remote : Text | Environment : Text | Missing >.Missing
+{ _1 =
+	< Local : Text | Remote : Text | Environment : Text | Missing >.Local
+	"./dhall-lang/tests/import/success/some/import.dhall"
+, _2 =
+	< Local : Text | Remote : Text | Environment : Text | Missing >.Local
+	"./dhall-lang/tests/import/data/simple.dhall"
+, _3 =
+	< Local : Text | Remote : Text | Environment : Text | Missing >.Local
+	"/absolute/import"
+, _4 =
+	< Local : Text | Remote : Text | Environment : Text | Missing >.Remote
+	"https://prelude.dhall-lang.org/package.dhall"
+, _5 =
+	< Local : Text | Remote : Text | Environment : Text | Missing >.Environment
+	"env:HOME"
+, _6 =
+	< Local : Text | Remote : Text | Environment : Text | Missing >.Missing
+, _7 =
+	< Local : Text | Remote : Text | Environment : Text | Missing >.Missing
 }
diff --git a/dhall-lang/tests/import/success/nestedHashA.dhall b/dhall-lang/tests/import/success/nestedHashA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/import/success/nestedHashA.dhall
@@ -0,0 +1,1 @@
+../data/nested.dhall sha256:add9792d79d9e03918e3236f32c6f8e89dbc05efac3451eb835676275f2c20a5
diff --git a/dhall-lang/tests/import/success/nestedHashB.dhall b/dhall-lang/tests/import/success/nestedHashB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/import/success/nestedHashB.dhall
@@ -0,0 +1,1 @@
+{ x = 3 }
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/and/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/and/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/and/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/and [ True, False, True ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/and/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/and/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/and/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/and/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/and/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/and/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/and ([] : List Bool)
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/and/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/and/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/and/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/build/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/build/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/build/0A.dhall
+++ /dev/null
@@ -1,2 +0,0 @@
-../../../../../../Prelude/Bool/build 
-(λ(bool : Type) → λ(true : bool) → λ(false : bool) → true)
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/build/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/build/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/build/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/build/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/build/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/build/1A.dhall
+++ /dev/null
@@ -1,2 +0,0 @@
-../../../../../../Prelude/Bool/build 
-(λ(bool : Type) → λ(true : bool) → λ(false : bool) → false)
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/build/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/build/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/build/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/even/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/even/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/even/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/even [ False, True, False ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/even/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/even/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/even/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/even/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/even/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/even/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/even [ False, True ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/even/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/even/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/even/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/even/2A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/even/2A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/even/2A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/even [ False ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/even/2B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/even/2B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/even/2B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/even/3A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/even/3A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/even/3A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/even ([] : List Bool)
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/even/3B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/even/3B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/even/3B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/fold/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/fold/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/fold/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/fold True Natural 0 1
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/fold/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/fold/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/fold/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-0
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/fold/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/fold/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/fold/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/fold False Natural 0 1
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/fold/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/fold/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/fold/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-1
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/not/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/not/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/not/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/not True
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/not/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/not/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/not/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/not/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/not/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/not/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/not False
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/not/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/not/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/not/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/odd/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/odd/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/odd/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/odd [ True, False, True ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/odd/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/odd/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/odd/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/odd/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/odd/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/odd/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/odd [ True, False ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/odd/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/odd/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/odd/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/odd/2A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/odd/2A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/odd/2A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/odd [ True ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/odd/2B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/odd/2B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/odd/2B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/odd/3A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/odd/3A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/odd/3A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/odd ([] : List Bool)
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/odd/3B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/odd/3B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/odd/3B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/or/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/or/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/or/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/or [ True, False, True ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/or/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/or/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/or/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/or/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/or/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/or/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/or ([] : List Bool)
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/or/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/or/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/or/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/show/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/show/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/show/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/show True
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/show/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/show/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/show/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"True"
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/show/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/show/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/show/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Bool/show False
diff --git a/dhall-lang/tests/normalization/success/prelude/Bool/show/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Bool/show/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Bool/show/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"False"
diff --git a/dhall-lang/tests/normalization/success/prelude/Double/show/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Double/show/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Double/show/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Double/show -3.1
diff --git a/dhall-lang/tests/normalization/success/prelude/Double/show/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Double/show/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Double/show/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"-3.1"
diff --git a/dhall-lang/tests/normalization/success/prelude/Double/show/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Double/show/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Double/show/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Double/show 0.4
diff --git a/dhall-lang/tests/normalization/success/prelude/Double/show/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Double/show/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Double/show/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"0.4"
diff --git a/dhall-lang/tests/normalization/success/prelude/Integer/show/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Integer/show/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Integer/show/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Integer/show -3
diff --git a/dhall-lang/tests/normalization/success/prelude/Integer/show/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Integer/show/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Integer/show/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"-3"
diff --git a/dhall-lang/tests/normalization/success/prelude/Integer/show/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Integer/show/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Integer/show/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Integer/show +0
diff --git a/dhall-lang/tests/normalization/success/prelude/Integer/show/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Integer/show/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Integer/show/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"+0"
diff --git a/dhall-lang/tests/normalization/success/prelude/Integer/toDouble/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Integer/toDouble/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Integer/toDouble/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Integer/toDouble -3
diff --git a/dhall-lang/tests/normalization/success/prelude/Integer/toDouble/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Integer/toDouble/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Integer/toDouble/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
--3.0
diff --git a/dhall-lang/tests/normalization/success/prelude/Integer/toDouble/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Integer/toDouble/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Integer/toDouble/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Integer/toDouble +2
diff --git a/dhall-lang/tests/normalization/success/prelude/Integer/toDouble/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Integer/toDouble/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Integer/toDouble/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-2.0
diff --git a/dhall-lang/tests/normalization/success/prelude/List/all/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/all/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/all/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/all Natural Natural/even [ 2, 3, 5 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/all/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/all/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/all/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/List/all/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/all/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/all/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/all Natural Natural/even ([] : List Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/List/all/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/all/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/all/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/List/any/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/any/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/any/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/any Natural Natural/even [ 2, 3, 5 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/any/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/any/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/any/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/List/any/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/any/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/any/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/any Natural Natural/even ([] : List Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/List/any/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/any/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/any/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/List/build/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/build/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/build/0A.dhall
+++ /dev/null
@@ -1,7 +0,0 @@
-../../../../../../Prelude/List/build
-Text
-( λ(list : Type)
-→ λ(cons : Text → list → list)
-→ λ(nil : list)
-→ cons "ABC" (cons "DEF" nil)
-)
diff --git a/dhall-lang/tests/normalization/success/prelude/List/build/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/build/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/build/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[ "ABC", "DEF" ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/build/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/build/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/build/1A.dhall
+++ /dev/null
@@ -1,7 +0,0 @@
-../../../../../../Prelude/List/build
-Text
-( λ(list : Type)
-→ λ(cons : Text → list → list)
-→ λ(nil : list)
-→ nil
-)
diff --git a/dhall-lang/tests/normalization/success/prelude/List/build/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/build/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/build/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[] : List Text
diff --git a/dhall-lang/tests/normalization/success/prelude/List/concat/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/concat/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/concat/0A.dhall
+++ /dev/null
@@ -1,5 +0,0 @@
-../../../../../../Prelude/List/concat Natural
-[ [ 0, 1, 2 ]
-, [ 3, 4 ]
-, [ 5, 6, 7, 8 ]
-]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/concat/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/concat/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/concat/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/concat/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/concat/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/concat/1A.dhall
+++ /dev/null
@@ -1,5 +0,0 @@
-../../../../../../Prelude/List/concat Natural
-[ [] : List Natural
-, [] : List Natural
-, [] : List Natural
-]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/concat/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/concat/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/concat/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[] : List Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/List/concatMap/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/concatMap/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/concatMap/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/concatMap Natural Natural (λ(n : Natural) → [ n, n ]) [ 2, 3, 5 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/concatMap/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/concatMap/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/concatMap/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[ 2, 2, 3, 3, 5, 5 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/concatMap/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/concatMap/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/concatMap/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/concatMap Natural Natural (λ(n : Natural) → [ n, n ]) ([] : List Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/List/concatMap/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/concatMap/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/concatMap/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[] : List Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/List/filter/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/filter/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/filter/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/filter Natural Natural/even [ 2, 3, 5 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/filter/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/filter/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/filter/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[ 2 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/filter/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/filter/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/filter/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/filter Natural Natural/odd [ 2, 3, 5 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/filter/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/filter/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/filter/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[ 3, 5 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/fold/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/fold/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/fold/0A.dhall
+++ /dev/null
@@ -1,6 +0,0 @@
-../../../../../../Prelude/List/fold
-Natural
-[ 2, 3, 5 ]
-Natural
-(λ(x : Natural) → λ(y : Natural) → x + y)
-0
diff --git a/dhall-lang/tests/normalization/success/prelude/List/fold/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/fold/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/fold/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-10
diff --git a/dhall-lang/tests/normalization/success/prelude/List/fold/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/fold/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/fold/1A.dhall
+++ /dev/null
@@ -1,7 +0,0 @@
-  λ(nil : Natural)
-→ ../../../../../../Prelude/List/fold
-  Natural
-  [ 2, 3, 5 ]
-  Natural
-  (λ(x : Natural) → λ(y : Natural) → x + y)
-  nil
diff --git a/dhall-lang/tests/normalization/success/prelude/List/fold/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/fold/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/fold/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-λ(nil : Natural) → 2 + (3 + (5 + nil))
diff --git a/dhall-lang/tests/normalization/success/prelude/List/fold/2A.dhall b/dhall-lang/tests/normalization/success/prelude/List/fold/2A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/fold/2A.dhall
+++ /dev/null
@@ -1,4 +0,0 @@
-  λ(list : Type)
-→ λ(cons : Natural → list → list)
-→ λ(nil : list)
-→ ../../../../../../Prelude/List/fold Natural [ 2, 3, 5 ] list cons nil
diff --git a/dhall-lang/tests/normalization/success/prelude/List/fold/2B.dhall b/dhall-lang/tests/normalization/success/prelude/List/fold/2B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/fold/2B.dhall
+++ /dev/null
@@ -1,4 +0,0 @@
-  λ(list : Type)
-→ λ(cons : Natural → list → list)
-→ λ(nil : list)
-→ cons 2 (cons 3 (cons 5 nil))
diff --git a/dhall-lang/tests/normalization/success/prelude/List/generate/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/generate/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/generate/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/generate 5 Bool Natural/even
diff --git a/dhall-lang/tests/normalization/success/prelude/List/generate/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/generate/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/generate/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[ True, False, True, False, True ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/generate/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/generate/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/generate/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/generate 0 Bool Natural/even
diff --git a/dhall-lang/tests/normalization/success/prelude/List/generate/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/generate/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/generate/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[] : List Bool
diff --git a/dhall-lang/tests/normalization/success/prelude/List/head/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/head/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/head/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/head Natural [ 0, 1, 2 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/head/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/head/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/head/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-Some 0
diff --git a/dhall-lang/tests/normalization/success/prelude/List/head/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/head/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/head/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/head Natural ([] : List Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/List/head/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/head/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/head/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-None Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/List/indexed/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/indexed/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/indexed/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/indexed Bool [ True, False, True ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/indexed/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/indexed/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/indexed/0B.dhall
+++ /dev/null
@@ -1,4 +0,0 @@
-[ { index = 0, value = True }
-, { index = 1, value = False }
-, { index = 2, value = True }
-]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/indexed/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/indexed/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/indexed/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/indexed Bool ([] : List Bool)
diff --git a/dhall-lang/tests/normalization/success/prelude/List/indexed/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/indexed/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/indexed/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[] : List { index : Natural, value : Bool }
diff --git a/dhall-lang/tests/normalization/success/prelude/List/iterate/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/iterate/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/iterate/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/iterate 10 Natural (λ(x : Natural) → x * 2) 1
diff --git a/dhall-lang/tests/normalization/success/prelude/List/iterate/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/iterate/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/iterate/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/iterate/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/iterate/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/iterate/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/iterate 0 Natural (λ(x : Natural) → x * 2) 1
diff --git a/dhall-lang/tests/normalization/success/prelude/List/iterate/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/iterate/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/iterate/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[] : List Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/List/last/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/last/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/last/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/last Natural [ 0, 1, 2 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/last/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/last/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/last/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-Some 2
diff --git a/dhall-lang/tests/normalization/success/prelude/List/last/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/last/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/last/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/last Natural ([] : List Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/List/last/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/last/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/last/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-None Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/List/length/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/length/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/length/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/length Natural [ 0, 1, 2 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/length/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/length/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/length/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-3
diff --git a/dhall-lang/tests/normalization/success/prelude/List/length/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/length/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/length/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/length Natural ([] : List Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/List/length/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/length/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/length/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-0
diff --git a/dhall-lang/tests/normalization/success/prelude/List/map/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/map/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/map/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/map Natural Bool Natural/even [ 2, 3, 5 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/map/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/map/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/map/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[ True, False, False ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/map/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/map/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/map/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/map Natural Bool Natural/even ([] : List Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/List/map/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/map/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/map/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[] : List Bool
diff --git a/dhall-lang/tests/normalization/success/prelude/List/null/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/null/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/null/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/null Natural [ 0, 1, 2 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/null/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/null/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/null/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/List/null/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/null/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/null/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/null Natural ([] : List Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/List/null/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/null/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/null/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/List/replicate/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/replicate/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/replicate/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/replicate 9 Natural 1
diff --git a/dhall-lang/tests/normalization/success/prelude/List/replicate/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/replicate/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/replicate/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[ 1, 1, 1, 1, 1, 1, 1, 1, 1 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/replicate/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/replicate/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/replicate/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/replicate 0 Natural 1
diff --git a/dhall-lang/tests/normalization/success/prelude/List/replicate/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/replicate/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/replicate/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[] : List Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/List/reverse/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/reverse/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/reverse/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/reverse Natural [ 0, 1, 2 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/reverse/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/reverse/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/reverse/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[ 2, 1, 0 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/reverse/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/reverse/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/reverse/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/reverse Natural ([] : List Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/List/reverse/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/reverse/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/reverse/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[] : List Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/List/shifted/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/shifted/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/shifted/0A.dhall
+++ /dev/null
@@ -1,15 +0,0 @@
-../../../../../../Prelude/List/shifted
-Bool
-[ [ { index = 0, value = True }
-  , { index = 1, value = True }
-  , { index = 2, value = False }
-  ]
-, [ { index = 0, value = False }
-  , { index = 1, value = False }
-  ]
-, [ { index = 0, value = True }
-  , { index = 1, value = True }
-  , { index = 2, value = True }
-  , { index = 3, value = True }
-  ]
-]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/shifted/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/shifted/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/shifted/0B.dhall
+++ /dev/null
@@ -1,10 +0,0 @@
-[ { index = 0, value = True }
-, { index = 1, value = True }
-, { index = 2, value = False }
-, { index = 3, value = False }
-, { index = 4, value = False }
-, { index = 5, value = True }
-, { index = 6, value = True }
-, { index = 7, value = True }
-, { index = 8, value = True }
-]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/shifted/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/shifted/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/shifted/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/shifted Bool ([] : List (List { index : Natural, value : Bool }))
diff --git a/dhall-lang/tests/normalization/success/prelude/List/shifted/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/shifted/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/shifted/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[] : List { index : Natural, value : Bool }
diff --git a/dhall-lang/tests/normalization/success/prelude/List/unzip/0A.dhall b/dhall-lang/tests/normalization/success/prelude/List/unzip/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/unzip/0A.dhall
+++ /dev/null
@@ -1,7 +0,0 @@
-../../../../../../Prelude/List/unzip
-Text
-Bool
-[ { _1 = "ABC", _2 = True }
-, { _1 = "DEF", _2 = False }
-, { _1 = "GHI", _2 = True }
-]
diff --git a/dhall-lang/tests/normalization/success/prelude/List/unzip/0B.dhall b/dhall-lang/tests/normalization/success/prelude/List/unzip/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/unzip/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-{ _1 = [ "ABC", "DEF", "GHI" ], _2 = [ True, False, True ] }
diff --git a/dhall-lang/tests/normalization/success/prelude/List/unzip/1A.dhall b/dhall-lang/tests/normalization/success/prelude/List/unzip/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/unzip/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/List/unzip Text Bool ([] : List { _1 : Text, _2 : Bool })
diff --git a/dhall-lang/tests/normalization/success/prelude/List/unzip/1B.dhall b/dhall-lang/tests/normalization/success/prelude/List/unzip/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/List/unzip/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-{ _1 = [] : List Text, _2 = [] : List Bool }
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/build/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/build/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/build/0A.dhall
+++ /dev/null
@@ -1,6 +0,0 @@
-../../../../../../Prelude/Natural/build
-( λ(natural : Type)
-→ λ(succ : natural → natural)
-→ λ(zero : natural)
-→ succ (succ (succ zero))
-)
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/build/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/build/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/build/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-3
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/build/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/build/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/build/1A.dhall
+++ /dev/null
@@ -1,6 +0,0 @@
-../../../../../../Prelude/Natural/build
-( λ(natural : Type)
-→ λ(succ : natural → natural)
-→ λ(zero : natural)
-→ zero
-)
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/build/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/build/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/build/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-0
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/enumerate/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/enumerate/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/enumerate/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/enumerate 10
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/enumerate/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/enumerate/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/enumerate/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/enumerate/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/enumerate/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/enumerate/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/enumerate 0
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/enumerate/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/enumerate/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/enumerate/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[] : List Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/even/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/even/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/even/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/even 3
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/even/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/even/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/even/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/even/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/even/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/even/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/even 0
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/even/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/even/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/even/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/fold/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/fold/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/fold/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/fold 3 Natural (λ(x : Natural) → 5 * x) 1
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/fold/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/fold/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/fold/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-125
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/fold/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/fold/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/fold/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-λ(zero : Natural) → ../../../../../../Prelude/Natural/fold 3 Natural (λ(x : Natural) → 5 * x) zero
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/fold/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/fold/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/fold/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-λ(zero : Natural) → 5 * (5 * (5 * zero))
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/fold/2A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/fold/2A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/fold/2A.dhall
+++ /dev/null
@@ -1,4 +0,0 @@
-  λ(natural : Type)
-→ λ(succ : natural → natural)
-→ λ(zero : natural)
-→ ../../../../../../Prelude/Natural/fold 3 natural succ zero
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/fold/2B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/fold/2B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/fold/2B.dhall
+++ /dev/null
@@ -1,4 +0,0 @@
-  λ(natural : Type)
-→ λ(succ : natural → natural)
-→ λ(zero : natural)
-→ succ (succ (succ zero))
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/isZero/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/isZero/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/isZero/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/isZero 2
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/isZero/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/isZero/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/isZero/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/isZero/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/isZero/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/isZero/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/isZero 0
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/isZero/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/isZero/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/isZero/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/odd/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/odd/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/odd/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/odd 3
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/odd/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/odd/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/odd/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/odd/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/odd/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/odd/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/odd 0
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/odd/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/odd/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/odd/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/product/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/product/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/product/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/product [ 2, 3, 5 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/product/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/product/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/product/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-30
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/product/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/product/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/product/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/product ([] : List Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/product/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/product/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/product/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-1
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/show/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/show/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/show/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/show 3
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/show/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/show/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/show/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"3"
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/show/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/show/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/show/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/show 0
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/show/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/show/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/show/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"0"
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/sum/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/sum/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/sum/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/sum [ 2, 3, 5 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/sum/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/sum/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/sum/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-10
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/sum/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/sum/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/sum/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/sum ([] : List Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/sum/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/sum/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/sum/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-0
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/toDouble/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/toDouble/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/toDouble/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/toDouble 3
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/toDouble/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/toDouble/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/toDouble/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-3.0
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/toDouble/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/toDouble/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/toDouble/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/toDouble 0
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/toDouble/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/toDouble/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/toDouble/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-0.0
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/toInteger/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/toInteger/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/toInteger/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/toInteger 3
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/toInteger/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/toInteger/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/toInteger/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-+3
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/toInteger/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/toInteger/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/toInteger/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Natural/toInteger 0
diff --git a/dhall-lang/tests/normalization/success/prelude/Natural/toInteger/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Natural/toInteger/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Natural/toInteger/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-+0
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/all/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/all/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/all/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/all Natural Natural/even (Some 3)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/all/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/all/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/all/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/all/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/all/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/all/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/all Natural Natural/even (None Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/all/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/all/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/all/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/any/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/any/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/any/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/any Natural Natural/even (Some 2)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/any/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/any/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/any/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/any/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/any/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/any/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/any Natural Natural/even (None Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/any/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/any/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/any/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/build/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/build/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/build/0A.dhall
+++ /dev/null
@@ -1,7 +0,0 @@
-../../../../../../Prelude/Optional/build
-Natural
-( λ(optional : Type)
-→ λ(some : Natural → optional)
-→ λ(none : optional)
-→ some 1
-)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/build/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/build/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/build/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-Some 1
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/build/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/build/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/build/1A.dhall
+++ /dev/null
@@ -1,7 +0,0 @@
-../../../../../../Prelude/Optional/build
-Natural
-( λ(optional : Type)
-→ λ(some : Natural → optional)
-→ λ(none : optional)
-→ none
-)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/build/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/build/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/build/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-None Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/concat/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/concat/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/concat/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/concat Natural (Some (Some 1))
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/concat/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/concat/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/concat/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-Some 1
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/concat/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/concat/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/concat/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/concat Natural (Some (None Natural))
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/concat/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/concat/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/concat/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-None Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/concat/2A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/concat/2A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/concat/2A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/concat Natural (None (Optional Natural))
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/concat/2B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/concat/2B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/concat/2B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-None Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/filter/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/filter/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/filter/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/filter Natural Natural/even (Some 2)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/filter/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/filter/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/filter/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-Some 2
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/filter/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/filter/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/filter/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/filter Natural Natural/odd (Some 2)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/filter/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/filter/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/filter/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-None Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/fold/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/fold/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/fold/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/fold Natural (Some 2) Natural (λ(x : Natural) → x) 0
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/fold/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/fold/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/fold/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-2
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/fold/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/fold/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/fold/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/fold Natural (None Natural) Natural (λ(x : Natural) → x) 0
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/fold/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/fold/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/fold/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-0
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/head/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/head/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/head/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/head Natural [ None Natural, Some 1, Some 2 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/head/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/head/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/head/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-Some 1
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/head/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/head/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/head/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/head Natural [ None Natural, None Natural ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/head/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/head/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/head/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-None Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/head/2A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/head/2A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/head/2A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/head Natural ([] : List (Optional Natural))
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/head/2B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/head/2B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/head/2B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-None Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/last/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/last/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/last/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/last Natural [ None Natural, Some 1, Some 2 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/last/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/last/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/last/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-Some 2
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/last/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/last/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/last/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/last Natural [ None Natural, None Natural ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/last/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/last/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/last/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-None Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/last/2A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/last/2A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/last/2A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/last Natural ([] : List (Optional Natural))
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/last/2B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/last/2B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/last/2B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-None Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/length/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/length/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/length/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/length Natural (Some 2)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/length/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/length/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/length/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-1
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/length/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/length/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/length/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/length Natural (None Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/length/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/length/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/length/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-0
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/map/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/map/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/map/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/map Natural Bool Natural/even (Some 3)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/map/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/map/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/map/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-Some False
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/map/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/map/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/map/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/map Natural Bool Natural/even (None Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/map/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/map/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/map/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-None Bool
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/null/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/null/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/null/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/null Natural (Some 2)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/null/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/null/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/null/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-False
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/null/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/null/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/null/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/null Natural (None Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/null/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/null/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/null/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-True
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/toList/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/toList/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/toList/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/toList Natural (Some 1)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/toList/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/toList/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/toList/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[ 1 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/toList/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/toList/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/toList/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/toList Natural (None Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/toList/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/toList/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/toList/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[] : List Natural
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/unzip/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/unzip/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/unzip/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/unzip Text Bool (Some { _1 = "ABC", _2 = True })
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/unzip/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/unzip/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/unzip/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-{ _1 = Some "ABC", _2 = Some True }
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/unzip/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/unzip/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/unzip/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Optional/unzip Text Bool (None { _1 : Text, _2 : Bool })
diff --git a/dhall-lang/tests/normalization/success/prelude/Optional/unzip/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Optional/unzip/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Optional/unzip/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-{ _1 = None Text, _2 = None Bool }
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concat/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concat/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concat/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Text/concat [ "ABC", "DEF", "GHI" ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concat/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concat/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concat/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"ABCDEFGHI"
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concat/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concat/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concat/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Text/concat ([] : List Text)
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concat/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concat/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concat/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-""
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concatMap/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concatMap/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concatMap/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Text/concatMap Natural (λ(n : Natural) → "${Natural/show n} ") [ 0, 1, 2 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concatMap/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concatMap/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concatMap/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"0 1 2 "
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concatMap/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concatMap/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concatMap/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Text/concatMap Natural (λ(n : Natural) → "${Natural/show n} ") ([] : List Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concatMap/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concatMap/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concatMap/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-""
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Text/concatMapSep ", " Natural Natural/show [ 0, 1, 2 ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"0, 1, 2"
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Text/concatMapSep ", " Natural Natural/show ([] : List Natural)
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-""
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concatSep/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concatSep/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concatSep/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Text/concatSep ", " [ "ABC", "DEF", "GHI" ]
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concatSep/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concatSep/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concatSep/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"ABC, DEF, GHI"
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concatSep/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concatSep/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concatSep/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Text/concatSep ", " ([] : List Text)
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/concatSep/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Text/concatSep/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/concatSep/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-""
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/show/0A.dhall b/dhall-lang/tests/normalization/success/prelude/Text/show/0A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/show/0A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Text/show "ABC"
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/show/0B.dhall b/dhall-lang/tests/normalization/success/prelude/Text/show/0B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/show/0B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"\"ABC\""
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/show/1A.dhall b/dhall-lang/tests/normalization/success/prelude/Text/show/1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/show/1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-../../../../../../Prelude/Text/show "\u0000 \$ \\ \n \u263a"
diff --git a/dhall-lang/tests/normalization/success/prelude/Text/show/1B.dhall b/dhall-lang/tests/normalization/success/prelude/Text/show/1B.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/prelude/Text/show/1B.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"\"\\u0000 \\u0024 \\\\ \\n ☺\""
diff --git a/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection0A.dhall b/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection0A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection0A.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : Bool, b : Bool }) → (x ⫽ { c = 0 }).{ a, c }.c
diff --git a/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection0B.dhall b/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection0B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection0B.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : Bool, b : Bool }) → 0
diff --git a/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection1A.dhall b/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection1A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection1A.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : Bool, b : Bool }) → (x ⫽ { c = 0 }).({ a : Bool, c : Natural }).a
diff --git a/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection1B.dhall b/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection1B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection1B.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : Bool, b : Bool }) → x.a
diff --git a/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecursiveRecordMergeWithinFieldselectionA.dhall b/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecursiveRecordMergeWithinFieldselectionA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecursiveRecordMergeWithinFieldselectionA.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : {} }) → (x ⫽ { b = 0 } ∧ { a = { c = 1 } }).b
diff --git a/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecursiveRecordMergeWithinFieldselectionB.dhall b/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecursiveRecordMergeWithinFieldselectionB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecursiveRecordMergeWithinFieldselectionB.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : {} }) → 0
diff --git a/dhall-lang/tests/normalization/success/unit/AssertNormalizeArgumentA.dhall b/dhall-lang/tests/normalization/success/unit/AssertNormalizeArgumentA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/AssertNormalizeArgumentA.dhall
@@ -0,0 +1,1 @@
+assert : (1 + 1) === (1 + 1)
diff --git a/dhall-lang/tests/normalization/success/unit/AssertNormalizeArgumentB.dhall b/dhall-lang/tests/normalization/success/unit/AssertNormalizeArgumentB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/AssertNormalizeArgumentB.dhall
@@ -0,0 +1,1 @@
+assert : 2 ≡ 2
diff --git a/dhall-lang/tests/normalization/success/unit/BareInterpolationA.dhall b/dhall-lang/tests/normalization/success/unit/BareInterpolationA.dhall
--- a/dhall-lang/tests/normalization/success/unit/BareInterpolationA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/BareInterpolationA.dhall
@@ -1,1 +1,1 @@
-"${x}"
+λ(x : Text) → "${x}"
diff --git a/dhall-lang/tests/normalization/success/unit/BareInterpolationB.dhall b/dhall-lang/tests/normalization/success/unit/BareInterpolationB.dhall
--- a/dhall-lang/tests/normalization/success/unit/BareInterpolationB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/BareInterpolationB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Text) → x
diff --git a/dhall-lang/tests/normalization/success/unit/EquivalenceNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/EquivalenceNormalizeArgumentsA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/EquivalenceNormalizeArgumentsA.dhall
@@ -0,0 +1,1 @@
+(1 + 1) === (1 + 2)
diff --git a/dhall-lang/tests/normalization/success/unit/EquivalenceNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/EquivalenceNormalizeArgumentsB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/EquivalenceNormalizeArgumentsB.dhall
@@ -0,0 +1,1 @@
+2 ≡ 3
diff --git a/dhall-lang/tests/normalization/success/unit/FunctionApplicationCaptureA.dhall b/dhall-lang/tests/normalization/success/unit/FunctionApplicationCaptureA.dhall
--- a/dhall-lang/tests/normalization/success/unit/FunctionApplicationCaptureA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/FunctionApplicationCaptureA.dhall
@@ -1,1 +1,1 @@
-(λ(_ : X) → λ(_ : X) → _@1) x y
+(λ(_ : Bool) → λ(_ : Bool) → _@1) True False
diff --git a/dhall-lang/tests/normalization/success/unit/FunctionApplicationCaptureB.dhall b/dhall-lang/tests/normalization/success/unit/FunctionApplicationCaptureB.dhall
--- a/dhall-lang/tests/normalization/success/unit/FunctionApplicationCaptureB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/FunctionApplicationCaptureB.dhall
@@ -1,1 +1,1 @@
-x
+True
diff --git a/dhall-lang/tests/normalization/success/unit/FunctionApplicationNoSubstituteA.dhall b/dhall-lang/tests/normalization/success/unit/FunctionApplicationNoSubstituteA.dhall
--- a/dhall-lang/tests/normalization/success/unit/FunctionApplicationNoSubstituteA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/FunctionApplicationNoSubstituteA.dhall
@@ -1,1 +1,1 @@
-(λ(x : X) → y) x
+λ(y : Bool) → (λ(x : Bool) → y) True
diff --git a/dhall-lang/tests/normalization/success/unit/FunctionApplicationNoSubstituteB.dhall b/dhall-lang/tests/normalization/success/unit/FunctionApplicationNoSubstituteB.dhall
--- a/dhall-lang/tests/normalization/success/unit/FunctionApplicationNoSubstituteB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/FunctionApplicationNoSubstituteB.dhall
@@ -1,1 +1,1 @@
-y
+λ(y : Bool) → y
diff --git a/dhall-lang/tests/normalization/success/unit/FunctionApplicationNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/FunctionApplicationNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/FunctionApplicationNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/FunctionApplicationNormalizeArgumentsA.dhall
@@ -1,1 +1,3 @@
-(if True then a else b) (if True then y else z)
+  λ(f : Bool → Natural)
+→ λ(x : Bool)
+→ (if True then f else f) (if True then x else x)
diff --git a/dhall-lang/tests/normalization/success/unit/FunctionApplicationNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/FunctionApplicationNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/FunctionApplicationNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/FunctionApplicationNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-a y
+λ(f : Bool → Natural) → λ(x : Bool) → f x
diff --git a/dhall-lang/tests/normalization/success/unit/FunctionApplicationSubstituteA.dhall b/dhall-lang/tests/normalization/success/unit/FunctionApplicationSubstituteA.dhall
--- a/dhall-lang/tests/normalization/success/unit/FunctionApplicationSubstituteA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/FunctionApplicationSubstituteA.dhall
@@ -1,1 +1,1 @@
-(λ(x : X) → x) y
+(λ(x : Bool) → x) True
diff --git a/dhall-lang/tests/normalization/success/unit/FunctionApplicationSubstituteB.dhall b/dhall-lang/tests/normalization/success/unit/FunctionApplicationSubstituteB.dhall
--- a/dhall-lang/tests/normalization/success/unit/FunctionApplicationSubstituteB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/FunctionApplicationSubstituteB.dhall
@@ -1,1 +1,1 @@
-y
+True
diff --git a/dhall-lang/tests/normalization/success/unit/FunctionNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/FunctionNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/FunctionNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/FunctionNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-λ(_ : if True then X else Y) → if True then _ else y
+let id = λ(X : Type) → X in λ(x : id Bool) → if True then x else x
diff --git a/dhall-lang/tests/normalization/success/unit/FunctionNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/FunctionNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/FunctionNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/FunctionNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-λ(_ : X) → _
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/FunctionTypeNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/FunctionTypeNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/FunctionTypeNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/FunctionTypeNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-(if True then X else Y) → if True then A else B
+let id = λ(X : Type) → X in id Bool → id Natural
diff --git a/dhall-lang/tests/normalization/success/unit/FunctionTypeNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/FunctionTypeNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/FunctionTypeNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/FunctionTypeNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-X → A
+Bool → Natural
diff --git a/dhall-lang/tests/normalization/success/unit/IfAlternativesIdenticalA.dhall b/dhall-lang/tests/normalization/success/unit/IfAlternativesIdenticalA.dhall
--- a/dhall-lang/tests/normalization/success/unit/IfAlternativesIdenticalA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/IfAlternativesIdenticalA.dhall
@@ -1,1 +1,1 @@
-if x then y else y
+λ(x : Bool) → λ(y : Natural) → if x then y else y
diff --git a/dhall-lang/tests/normalization/success/unit/IfAlternativesIdenticalB.dhall b/dhall-lang/tests/normalization/success/unit/IfAlternativesIdenticalB.dhall
--- a/dhall-lang/tests/normalization/success/unit/IfAlternativesIdenticalB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/IfAlternativesIdenticalB.dhall
@@ -1,1 +1,1 @@
-y
+λ(x : Bool) → λ(y : Natural) → y
diff --git a/dhall-lang/tests/normalization/success/unit/IfNormalizePredicateAndBranchesA.dhall b/dhall-lang/tests/normalization/success/unit/IfNormalizePredicateAndBranchesA.dhall
--- a/dhall-lang/tests/normalization/success/unit/IfNormalizePredicateAndBranchesA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/IfNormalizePredicateAndBranchesA.dhall
@@ -1,1 +1,4 @@
-if if True then x else y then if True then a else b else if True then c else d
+  λ(b : Bool)
+→ λ(x : Natural)
+→ λ(y : Natural)
+→ if if True then b else b then if True then x else x else if True then y else y
diff --git a/dhall-lang/tests/normalization/success/unit/IfNormalizePredicateAndBranchesB.dhall b/dhall-lang/tests/normalization/success/unit/IfNormalizePredicateAndBranchesB.dhall
--- a/dhall-lang/tests/normalization/success/unit/IfNormalizePredicateAndBranchesB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/IfNormalizePredicateAndBranchesB.dhall
@@ -1,1 +1,1 @@
-if x then a else c
+λ(b : Bool) → λ(x : Natural) → λ(y : Natural) → if b then x else y
diff --git a/dhall-lang/tests/normalization/success/unit/IfTrivialA.dhall b/dhall-lang/tests/normalization/success/unit/IfTrivialA.dhall
--- a/dhall-lang/tests/normalization/success/unit/IfTrivialA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/IfTrivialA.dhall
@@ -1,1 +1,1 @@
-if x then True else False
+λ(x : Bool) → if x then True else False
diff --git a/dhall-lang/tests/normalization/success/unit/IfTrivialB.dhall b/dhall-lang/tests/normalization/success/unit/IfTrivialB.dhall
--- a/dhall-lang/tests/normalization/success/unit/IfTrivialB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/IfTrivialB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/LetA.dhall b/dhall-lang/tests/normalization/success/unit/LetA.dhall
--- a/dhall-lang/tests/normalization/success/unit/LetA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/LetA.dhall
@@ -1,1 +1,1 @@
-let x = y in x
+λ(y : Bool) → let x = y in x
diff --git a/dhall-lang/tests/normalization/success/unit/LetB.dhall b/dhall-lang/tests/normalization/success/unit/LetB.dhall
--- a/dhall-lang/tests/normalization/success/unit/LetB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/LetB.dhall
@@ -1,1 +1,1 @@
-y
+λ(y : Bool) → y
diff --git a/dhall-lang/tests/normalization/success/unit/LetWithTypeA.dhall b/dhall-lang/tests/normalization/success/unit/LetWithTypeA.dhall
--- a/dhall-lang/tests/normalization/success/unit/LetWithTypeA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/LetWithTypeA.dhall
@@ -1,1 +1,1 @@
-let x : A = y in x
+λ(y : Bool) → let x : Bool = y in x
diff --git a/dhall-lang/tests/normalization/success/unit/LetWithTypeB.dhall b/dhall-lang/tests/normalization/success/unit/LetWithTypeB.dhall
--- a/dhall-lang/tests/normalization/success/unit/LetWithTypeB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/LetWithTypeB.dhall
@@ -1,1 +1,1 @@
-y
+λ(y : Bool) → y
diff --git a/dhall-lang/tests/normalization/success/unit/ListBuildFoldFusionA.dhall b/dhall-lang/tests/normalization/success/unit/ListBuildFoldFusionA.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListBuildFoldFusionA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListBuildFoldFusionA.dhall
@@ -1,1 +1,1 @@
-List/build A (List/fold A x)
+λ(T : Type) → λ(x : List T) → List/build T (List/fold T x)
diff --git a/dhall-lang/tests/normalization/success/unit/ListBuildFoldFusionB.dhall b/dhall-lang/tests/normalization/success/unit/ListBuildFoldFusionB.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListBuildFoldFusionB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListBuildFoldFusionB.dhall
@@ -1,1 +1,1 @@
-x
+λ(T : Type) → λ(x : List T) → x
diff --git a/dhall-lang/tests/normalization/success/unit/ListBuildImplementationA.dhall b/dhall-lang/tests/normalization/success/unit/ListBuildImplementationA.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListBuildImplementationA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListBuildImplementationA.dhall
@@ -1,1 +1,3 @@
-List/build A0 (λ(list : Type) → λ(cons : A0 → list → list) → λ(nil : list) → x)
+  λ(T : Type)
+→ λ(f : ∀(list : Type) → (T → list → list) → list → list)
+→ List/build T f
diff --git a/dhall-lang/tests/normalization/success/unit/ListBuildImplementationB.dhall b/dhall-lang/tests/normalization/success/unit/ListBuildImplementationB.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListBuildImplementationB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListBuildImplementationB.dhall
@@ -1,1 +1,3 @@
-x
+  λ(T : Type)
+→ λ(f : ∀(list : Type) → (T → list → list) → list → list)
+→ f (List T) (λ(a : T) → λ(`as` : List T) → [ a ] # `as`) ([] : List T)
diff --git a/dhall-lang/tests/normalization/success/unit/ListFoldEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/ListFoldEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListFoldEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListFoldEmptyA.dhall
@@ -1,1 +1,1 @@
-List/fold A0 ([] : List A1) B g x
+λ(T : Type) → λ(f : T → Bool → Bool) → List/fold T ([] : List T) Bool f True
diff --git a/dhall-lang/tests/normalization/success/unit/ListFoldEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/ListFoldEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListFoldEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListFoldEmptyB.dhall
@@ -1,1 +1,1 @@
-x
+λ(T : Type) → λ(f : T → Bool → Bool) → True
diff --git a/dhall-lang/tests/normalization/success/unit/ListFoldOneA.dhall b/dhall-lang/tests/normalization/success/unit/ListFoldOneA.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListFoldOneA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListFoldOneA.dhall
@@ -1,1 +1,1 @@
-List/fold A0 [ x ] B (λ(x : A0) → λ(y : B) → x) z
+λ(T : Type) → λ(f : T → Bool → Bool) → λ(x : T) → List/fold T [ x ] Bool f True
diff --git a/dhall-lang/tests/normalization/success/unit/ListFoldOneB.dhall b/dhall-lang/tests/normalization/success/unit/ListFoldOneB.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListFoldOneB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListFoldOneB.dhall
@@ -1,1 +1,1 @@
-x
+λ(T : Type) → λ(f : T → Bool → Bool) → λ(x : T) → f x True
diff --git a/dhall-lang/tests/normalization/success/unit/ListHeadEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/ListHeadEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListHeadEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListHeadEmptyA.dhall
@@ -1,1 +1,1 @@
-List/head T ([] : List T)
+λ(T : Type) → List/head T ([] : List T)
diff --git a/dhall-lang/tests/normalization/success/unit/ListHeadEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/ListHeadEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListHeadEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListHeadEmptyB.dhall
@@ -1,1 +1,1 @@
-None T
+λ(T : Type) → None T
diff --git a/dhall-lang/tests/normalization/success/unit/ListIndexedEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/ListIndexedEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListIndexedEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListIndexedEmptyA.dhall
@@ -1,1 +1,1 @@
-List/indexed T ([] : List T)
+λ(T : Type) → List/indexed T ([] : List T)
diff --git a/dhall-lang/tests/normalization/success/unit/ListIndexedEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/ListIndexedEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListIndexedEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListIndexedEmptyB.dhall
@@ -1,1 +1,1 @@
-[] : List { index : Natural, value : T }
+λ(T : Type) → [] : List { index : Natural, value : T }
diff --git a/dhall-lang/tests/normalization/success/unit/ListLastEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/ListLastEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListLastEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListLastEmptyA.dhall
@@ -1,1 +1,1 @@
-List/last T ([] : List T)
+λ(T : Type) → List/last T ([] : List T)
diff --git a/dhall-lang/tests/normalization/success/unit/ListLastEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/ListLastEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListLastEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListLastEmptyB.dhall
@@ -1,1 +1,1 @@
-None T
+λ(T : Type) → None T
diff --git a/dhall-lang/tests/normalization/success/unit/ListLengthEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/ListLengthEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListLengthEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListLengthEmptyA.dhall
@@ -1,1 +1,1 @@
-List/length T ([] : List T)
+λ(T : Type) → List/length T ([] : List T)
diff --git a/dhall-lang/tests/normalization/success/unit/ListLengthEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/ListLengthEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListLengthEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListLengthEmptyB.dhall
@@ -1,1 +1,1 @@
-0
+λ(T : Type) → 0
diff --git a/dhall-lang/tests/normalization/success/unit/ListNormalizeElementsA.dhall b/dhall-lang/tests/normalization/success/unit/ListNormalizeElementsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListNormalizeElementsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListNormalizeElementsA.dhall
@@ -1,1 +1,1 @@
-[ if True then x else y ]
+λ(x : Bool) → [ if True then x else x ]
diff --git a/dhall-lang/tests/normalization/success/unit/ListNormalizeElementsB.dhall b/dhall-lang/tests/normalization/success/unit/ListNormalizeElementsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListNormalizeElementsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListNormalizeElementsB.dhall
@@ -1,1 +1,1 @@
-[ x ]
+λ(x : Bool) → [ x ]
diff --git a/dhall-lang/tests/normalization/success/unit/ListReverseEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/ListReverseEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListReverseEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListReverseEmptyA.dhall
@@ -1,1 +1,1 @@
-List/reverse T ([] : List T)
+λ(T : Type) → List/reverse T ([] : List T)
diff --git a/dhall-lang/tests/normalization/success/unit/ListReverseEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/ListReverseEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/ListReverseEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/ListReverseEmptyB.dhall
@@ -1,1 +1,1 @@
-[] : List T
+λ(T : Type) → [] : List T
diff --git a/dhall-lang/tests/normalization/success/unit/MergeA.dhall b/dhall-lang/tests/normalization/success/unit/MergeA.dhall
--- a/dhall-lang/tests/normalization/success/unit/MergeA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/MergeA.dhall
@@ -1,1 +1,1 @@
-merge { x = λ(_ : A) → _ } (< x : T >.x y)
+λ(T : Type) → λ(f : T → Bool) → λ(x : T) → merge { a = f } (< a : T >.a x)
diff --git a/dhall-lang/tests/normalization/success/unit/MergeB.dhall b/dhall-lang/tests/normalization/success/unit/MergeB.dhall
--- a/dhall-lang/tests/normalization/success/unit/MergeB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/MergeB.dhall
@@ -1,1 +1,1 @@
-y
+λ(T : Type) → λ(f : T → Bool) → λ(x : T) → f x
diff --git a/dhall-lang/tests/normalization/success/unit/MergeEmptyAlternativeA.dhall b/dhall-lang/tests/normalization/success/unit/MergeEmptyAlternativeA.dhall
--- a/dhall-lang/tests/normalization/success/unit/MergeEmptyAlternativeA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/MergeEmptyAlternativeA.dhall
@@ -1,1 +1,1 @@
-merge { x = a } < x >.x
+λ(x : Bool) → merge { a = x } < a >.a
diff --git a/dhall-lang/tests/normalization/success/unit/MergeEmptyAlternativeB.dhall b/dhall-lang/tests/normalization/success/unit/MergeEmptyAlternativeB.dhall
--- a/dhall-lang/tests/normalization/success/unit/MergeEmptyAlternativeB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/MergeEmptyAlternativeB.dhall
@@ -1,1 +1,1 @@
-a
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/MergeNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/MergeNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/MergeNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/MergeNormalizeArgumentsA.dhall
@@ -1,1 +1,3 @@
-merge (if True then x else y) (if True then z else b)
+  λ(x : { a : Bool })
+→ λ(y : < a >)
+→ merge (if True then x else x) (if True then y else y)
diff --git a/dhall-lang/tests/normalization/success/unit/MergeNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/MergeNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/MergeNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/MergeNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-merge x z
+λ(x : { a : Bool }) → λ(y : < a >) → merge x y
diff --git a/dhall-lang/tests/normalization/success/unit/MergeWithTypeA.dhall b/dhall-lang/tests/normalization/success/unit/MergeWithTypeA.dhall
--- a/dhall-lang/tests/normalization/success/unit/MergeWithTypeA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/MergeWithTypeA.dhall
@@ -1,1 +1,4 @@
-merge { x = λ(_ : A) → _ } (< x : T >.x y) : A
+  λ(T : Type)
+→ λ(f : T → Bool)
+→ λ(x : T)
+→ merge { a = f } (< a : T >.a x) : Bool
diff --git a/dhall-lang/tests/normalization/success/unit/MergeWithTypeB.dhall b/dhall-lang/tests/normalization/success/unit/MergeWithTypeB.dhall
--- a/dhall-lang/tests/normalization/success/unit/MergeWithTypeB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/MergeWithTypeB.dhall
@@ -1,1 +1,1 @@
-y
+λ(T : Type) → λ(f : T → Bool) → λ(x : T) → f x
diff --git a/dhall-lang/tests/normalization/success/unit/MergeWithTypeNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/MergeWithTypeNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/MergeWithTypeNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/MergeWithTypeNormalizeArgumentsA.dhall
@@ -1,1 +1,5 @@
-merge (if True then x else y) (if True then z else b) : (if True then X else Y)
+let id = λ(X : Type) → X
+
+in    λ(x : { a : Bool })
+    → λ(y : < a >)
+    → merge (if True then x else x) (if True then y else y) : id Bool
diff --git a/dhall-lang/tests/normalization/success/unit/MergeWithTypeNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/MergeWithTypeNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/MergeWithTypeNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/MergeWithTypeNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-merge x z : X
+λ(x : { a : Bool }) → λ(y : < a >) → merge x y : Bool
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalBuildFoldFusionA.dhall b/dhall-lang/tests/normalization/success/unit/NaturalBuildFoldFusionA.dhall
--- a/dhall-lang/tests/normalization/success/unit/NaturalBuildFoldFusionA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/NaturalBuildFoldFusionA.dhall
@@ -1,1 +1,1 @@
-Natural/build (Natural/fold x)
+λ(x : Natural) → Natural/build (Natural/fold x)
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalBuildFoldFusionB.dhall b/dhall-lang/tests/normalization/success/unit/NaturalBuildFoldFusionB.dhall
--- a/dhall-lang/tests/normalization/success/unit/NaturalBuildFoldFusionB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/NaturalBuildFoldFusionB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Natural) → x
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalBuildImplementationA.dhall b/dhall-lang/tests/normalization/success/unit/NaturalBuildImplementationA.dhall
--- a/dhall-lang/tests/normalization/success/unit/NaturalBuildImplementationA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/NaturalBuildImplementationA.dhall
@@ -1,2 +1,2 @@
-Natural/build
-(λ(natural : Type) → λ(succ : natural → natural) → λ(zero : natural) → x)
+  λ(f : ∀(natural : Type) → (natural → natural) → natural → natural)
+→ Natural/build f
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalBuildImplementationB.dhall b/dhall-lang/tests/normalization/success/unit/NaturalBuildImplementationB.dhall
--- a/dhall-lang/tests/normalization/success/unit/NaturalBuildImplementationB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/NaturalBuildImplementationB.dhall
@@ -1,1 +1,2 @@
-x
+  λ(f : ∀(natural : Type) → (natural → natural) → natural → natural)
+→ f Natural (λ(x : Natural) → x + 1) 0
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalFoldOneA.dhall b/dhall-lang/tests/normalization/success/unit/NaturalFoldOneA.dhall
--- a/dhall-lang/tests/normalization/success/unit/NaturalFoldOneA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/NaturalFoldOneA.dhall
@@ -1,1 +1,1 @@
-Natural/fold 1 Natural (λ(x : Natural) → 5) x
+λ(x : Bool) → Natural/fold 1 Bool (λ(_ : Bool) → True) x
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalFoldOneB.dhall b/dhall-lang/tests/normalization/success/unit/NaturalFoldOneB.dhall
--- a/dhall-lang/tests/normalization/success/unit/NaturalFoldOneB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/NaturalFoldOneB.dhall
@@ -1,1 +1,1 @@
-5
+λ(x : Bool) → True
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalFoldZeroA.dhall b/dhall-lang/tests/normalization/success/unit/NaturalFoldZeroA.dhall
--- a/dhall-lang/tests/normalization/success/unit/NaturalFoldZeroA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/NaturalFoldZeroA.dhall
@@ -1,1 +1,1 @@
-Natural/fold 0 B g x
+λ(x : Bool) → Natural/fold 0 Bool (λ(_ : Bool) → True) x
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalFoldZeroB.dhall b/dhall-lang/tests/normalization/success/unit/NaturalFoldZeroB.dhall
--- a/dhall-lang/tests/normalization/success/unit/NaturalFoldZeroB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/NaturalFoldZeroB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalSubtractEquivalentA.dhall b/dhall-lang/tests/normalization/success/unit/NaturalSubtractEquivalentA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/NaturalSubtractEquivalentA.dhall
@@ -0,0 +1,1 @@
+λ(x : Natural) → Natural/subtract x x
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalSubtractEquivalentB.dhall b/dhall-lang/tests/normalization/success/unit/NaturalSubtractEquivalentB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/NaturalSubtractEquivalentB.dhall
@@ -0,0 +1,1 @@
+λ(x : Natural) → 0
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalSubtractFromZeroA.dhall b/dhall-lang/tests/normalization/success/unit/NaturalSubtractFromZeroA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/NaturalSubtractFromZeroA.dhall
@@ -0,0 +1,1 @@
+λ(x : Natural) → Natural/subtract x 0
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalSubtractFromZeroB.dhall b/dhall-lang/tests/normalization/success/unit/NaturalSubtractFromZeroB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/NaturalSubtractFromZeroB.dhall
@@ -0,0 +1,1 @@
+λ(x : Natural) → 0
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalSubtractGreaterA.dhall b/dhall-lang/tests/normalization/success/unit/NaturalSubtractGreaterA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/NaturalSubtractGreaterA.dhall
@@ -0,0 +1,1 @@
+Natural/subtract 3 10
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalSubtractGreaterB.dhall b/dhall-lang/tests/normalization/success/unit/NaturalSubtractGreaterB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/NaturalSubtractGreaterB.dhall
@@ -0,0 +1,1 @@
+7
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalSubtractLessA.dhall b/dhall-lang/tests/normalization/success/unit/NaturalSubtractLessA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/NaturalSubtractLessA.dhall
@@ -0,0 +1,1 @@
+Natural/subtract 3 2
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalSubtractLessB.dhall b/dhall-lang/tests/normalization/success/unit/NaturalSubtractLessB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/NaturalSubtractLessB.dhall
@@ -0,0 +1,1 @@
+0
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalSubtractNormalizeA.dhall b/dhall-lang/tests/normalization/success/unit/NaturalSubtractNormalizeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/NaturalSubtractNormalizeA.dhall
@@ -0,0 +1,3 @@
+  λ(x : Natural)
+→ λ(y : Natural)
+→ Natural/subtract (if True then x else y) (10 + 20)
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalSubtractNormalizeB.dhall b/dhall-lang/tests/normalization/success/unit/NaturalSubtractNormalizeB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/NaturalSubtractNormalizeB.dhall
@@ -0,0 +1,1 @@
+λ(x : Natural) → λ(y : Natural) → Natural/subtract x 30
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalSubtractZero0A.dhall b/dhall-lang/tests/normalization/success/unit/NaturalSubtractZero0A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/NaturalSubtractZero0A.dhall
@@ -0,0 +1,1 @@
+λ(x : Natural) → Natural/subtract 0 x
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalSubtractZero0B.dhall b/dhall-lang/tests/normalization/success/unit/NaturalSubtractZero0B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/NaturalSubtractZero0B.dhall
@@ -0,0 +1,1 @@
+λ(x : Natural) → x
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalSubtractZero1A.dhall b/dhall-lang/tests/normalization/success/unit/NaturalSubtractZero1A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/NaturalSubtractZero1A.dhall
@@ -0,0 +1,1 @@
+Natural/subtract 0
diff --git a/dhall-lang/tests/normalization/success/unit/NaturalSubtractZero1B.dhall b/dhall-lang/tests/normalization/success/unit/NaturalSubtractZero1B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/NaturalSubtractZero1B.dhall
@@ -0,0 +1,1 @@
+Natural/subtract 0
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorAndEquivalentArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorAndEquivalentArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorAndEquivalentArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorAndEquivalentArgumentsA.dhall
@@ -1,1 +1,1 @@
-x && x
+λ(x : Bool) → x && x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorAndEquivalentArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorAndEquivalentArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorAndEquivalentArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorAndEquivalentArgumentsB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorAndLhsFalseA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorAndLhsFalseA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorAndLhsFalseA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorAndLhsFalseA.dhall
@@ -1,1 +1,1 @@
-False && x
+λ(x : Bool) → False && x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorAndLhsFalseB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorAndLhsFalseB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorAndLhsFalseB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorAndLhsFalseB.dhall
@@ -1,1 +1,1 @@
-False
+λ(x : Bool) → False
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorAndLhsTrueA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorAndLhsTrueA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorAndLhsTrueA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorAndLhsTrueA.dhall
@@ -1,1 +1,1 @@
-True && x
+λ(x : Bool) → True && x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorAndLhsTrueB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorAndLhsTrueB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorAndLhsTrueB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorAndLhsTrueB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorAndNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorAndNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorAndNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorAndNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-True && x && (True && y)
+λ(x : Bool) → λ(y : Bool) → True && x && (True && y)
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorAndNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorAndNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorAndNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorAndNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-x && y
+λ(x : Bool) → λ(y : Bool) → x && y
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorAndRhsFalseA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorAndRhsFalseA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorAndRhsFalseA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorAndRhsFalseA.dhall
@@ -1,1 +1,1 @@
-x && False
+λ(x : Bool) → x && False
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorAndRhsFalseB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorAndRhsFalseB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorAndRhsFalseB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorAndRhsFalseB.dhall
@@ -1,1 +1,1 @@
-False
+λ(x : Bool) → False
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorAndRhsTrueA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorAndRhsTrueA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorAndRhsTrueA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorAndRhsTrueA.dhall
@@ -1,1 +1,1 @@
-x && True
+λ(x : Bool) → x && True
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorAndRhsTrueB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorAndRhsTrueB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorAndRhsTrueB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorAndRhsTrueB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorEqualEquivalentArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorEqualEquivalentArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorEqualEquivalentArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorEqualEquivalentArgumentsA.dhall
@@ -1,1 +1,1 @@
-x == x
+λ(x : Bool) → x == x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorEqualEquivalentArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorEqualEquivalentArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorEqualEquivalentArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorEqualEquivalentArgumentsB.dhall
@@ -1,1 +1,1 @@
-True
+λ(x : Bool) → True
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorEqualLhsTrueA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorEqualLhsTrueA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorEqualLhsTrueA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorEqualLhsTrueA.dhall
@@ -1,1 +1,1 @@
-x == True
+λ(x : Bool) → x == True
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorEqualLhsTrueB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorEqualLhsTrueB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorEqualLhsTrueB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorEqualLhsTrueB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorEqualNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorEqualNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorEqualNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorEqualNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-True == x == (True == y)
+λ(x : Bool) → λ(y : Bool) → True == x == (True == y)
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorEqualNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorEqualNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorEqualNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorEqualNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-x == y
+λ(x : Bool) → λ(y : Bool) → x == y
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorEqualRhsTrueA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorEqualRhsTrueA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorEqualRhsTrueA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorEqualRhsTrueA.dhall
@@ -1,1 +1,1 @@
-True == x
+λ(x : Bool) → True == x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorEqualRhsTrueB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorEqualRhsTrueB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorEqualRhsTrueB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorEqualRhsTrueB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateLhsEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateLhsEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateLhsEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateLhsEmptyA.dhall
@@ -1,1 +1,1 @@
-x # ([] : List T)
+λ(T : Type) → λ(x : List T) → x # ([] : List T)
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateLhsEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateLhsEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateLhsEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateLhsEmptyB.dhall
@@ -1,1 +1,1 @@
-x
+λ(T : Type) → λ(x : List T) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateListListA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateListListA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateListListA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateListListA.dhall
@@ -1,1 +1,1 @@
-[ x ] # [ y ]
+λ(T : Type) → λ(x : T) → λ(y : T) → [ x ] # [ y ]
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateListListB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateListListB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateListListB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateListListB.dhall
@@ -1,1 +1,1 @@
-[ x, y ]
+λ(T : Type) → λ(x : T) → λ(y : T) → [ x, y ]
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateNormalizeArgumentsA.dhall
@@ -1,1 +1,4 @@
-([] : List T) # x # (([] : List T) # y)
+  λ(T : Type)
+→ λ(x : List T)
+→ λ(y : List T)
+→ ([] : List T) # x # (([] : List T) # y)
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-x # y
+λ(T : Type) → λ(x : List T) → λ(y : List T) → x # y
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateRhsEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateRhsEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateRhsEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateRhsEmptyA.dhall
@@ -1,1 +1,1 @@
-([] : List T) # x
+λ(T : Type) → λ(x : List T) → ([] : List T) # x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateRhsEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateRhsEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateRhsEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorListConcatenateRhsEmptyB.dhall
@@ -1,1 +1,1 @@
-x
+λ(T : Type) → λ(x : List T) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualEquivalentArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualEquivalentArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualEquivalentArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualEquivalentArgumentsA.dhall
@@ -1,1 +1,1 @@
-x != x
+λ(x : Bool) → x != x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualEquivalentArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualEquivalentArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualEquivalentArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualEquivalentArgumentsB.dhall
@@ -1,1 +1,1 @@
-False
+λ(x : Bool) → False
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualLhsFalseA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualLhsFalseA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualLhsFalseA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualLhsFalseA.dhall
@@ -1,1 +1,1 @@
-False != x
+λ(x : Bool) → False != x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualLhsFalseB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualLhsFalseB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualLhsFalseB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualLhsFalseB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-False != x != (False != y)
+λ(x : Bool) → λ(y : Bool) → False != x != (False != y)
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-x != y
+λ(x : Bool) → λ(y : Bool) → x != y
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualRhsFalseA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualRhsFalseA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualRhsFalseA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualRhsFalseA.dhall
@@ -1,1 +1,1 @@
-x != False
+λ(x : Bool) → x != False
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualRhsFalseB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualRhsFalseB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorNotEqualRhsFalseB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorNotEqualRhsFalseB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorOrEquivalentArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorOrEquivalentArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorOrEquivalentArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorOrEquivalentArgumentsA.dhall
@@ -1,1 +1,1 @@
-x || x
+λ(x : Bool) → x || x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorOrEquivalentArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorOrEquivalentArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorOrEquivalentArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorOrEquivalentArgumentsB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorOrLhsFalseA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorOrLhsFalseA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorOrLhsFalseA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorOrLhsFalseA.dhall
@@ -1,1 +1,1 @@
-False || x
+λ(x : Bool) → False || x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorOrLhsFalseB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorOrLhsFalseB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorOrLhsFalseB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorOrLhsFalseB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorOrLhsTrueA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorOrLhsTrueA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorOrLhsTrueA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorOrLhsTrueA.dhall
@@ -1,1 +1,1 @@
-True || x
+λ(x : Bool) → True || x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorOrLhsTrueB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorOrLhsTrueB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorOrLhsTrueB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorOrLhsTrueB.dhall
@@ -1,1 +1,1 @@
-True
+λ(x : Bool) → True
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorOrNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorOrNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorOrNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorOrNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-False || x || (False || y)
+λ(x : Bool) → λ(y : Bool) → False || x || (False || y)
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorOrNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorOrNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorOrNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorOrNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-x || y
+λ(x : Bool) → λ(y : Bool) → x || y
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorOrRhsFalseA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorOrRhsFalseA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorOrRhsFalseA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorOrRhsFalseA.dhall
@@ -1,1 +1,1 @@
-x || False
+λ(x : Bool) → x || False
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorOrRhsFalseB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorOrRhsFalseB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorOrRhsFalseB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorOrRhsFalseB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorOrRhsTrueA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorOrRhsTrueA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorOrRhsTrueA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorOrRhsTrueA.dhall
@@ -1,1 +1,1 @@
-x || True
+λ(x : Bool) → x || True
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorOrRhsTrueB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorOrRhsTrueB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorOrRhsTrueB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorOrRhsTrueB.dhall
@@ -1,1 +1,1 @@
-True
+λ(x : Bool) → True
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorPlusLhsZeroA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorPlusLhsZeroA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorPlusLhsZeroA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorPlusLhsZeroA.dhall
@@ -1,1 +1,1 @@
-0 + x
+λ(x : Natural) → 0 + x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorPlusLhsZeroB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorPlusLhsZeroB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorPlusLhsZeroB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorPlusLhsZeroB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Natural) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorPlusNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorPlusNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorPlusNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorPlusNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-0 + x + (0 + y)
+λ(x : Natural) → λ(y : Natural) → 0 + x + (0 + y)
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorPlusNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorPlusNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorPlusNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorPlusNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-x + y
+λ(x : Natural) → λ(y : Natural) → x + y
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorPlusRhsZeroA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorPlusRhsZeroA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorPlusRhsZeroA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorPlusRhsZeroA.dhall
@@ -1,1 +1,1 @@
-x + 0
+λ(x : Natural) → x + 0
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorPlusRhsZeroB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorPlusRhsZeroB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorPlusRhsZeroB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorPlusRhsZeroB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Natural) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsEmptyA.dhall
@@ -1,1 +1,1 @@
-"" ++ x
+λ(x : Text) → "" ++ x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsEmptyB.dhall
@@ -1,5 +1,1 @@
-{- The expected result is not `"${x}"`, because the standard requires that any
-   expression of the form `"${x}"` be simplified further to the equivalent
-   expression `x`
--}
-x
+λ(x : Text) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsNonEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsNonEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsNonEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsNonEmptyA.dhall
@@ -1,1 +1,1 @@
-"hai" ++ x
+λ(x : Text) → "hai" ++ x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsNonEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsNonEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsNonEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsNonEmptyB.dhall
@@ -1,1 +1,1 @@
-"hai${x}"
+λ(x : Text) → "hai${x}"
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyA.dhall
@@ -1,1 +1,1 @@
-x ++ ""
+λ(x : Text) → x ++ ""
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyB.dhall
@@ -1,5 +1,1 @@
-{- The expected result is not `"${x}"`, because the standard requires that any
-   expression of the form `"${x}"` be simplified further to the equivalent
-   expression `x`
--}
-x
+λ(x : Text) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyA.dhall
@@ -1,1 +1,1 @@
-x ++ "hai"
+λ(x : Text) → x ++ "hai"
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyB.dhall
@@ -1,1 +1,1 @@
-"${x}hai"
+λ(x : Text) → "${x}hai"
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsOneA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsOneA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsOneA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsOneA.dhall
@@ -1,1 +1,1 @@
-1 * x
+λ(x : Natural) → 1 * x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsOneB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsOneB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsOneB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsOneB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Natural) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsZeroA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsZeroA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsZeroA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsZeroA.dhall
@@ -1,1 +1,1 @@
-0 * x
+λ(x : Natural) → 0 * x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsZeroB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsZeroB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsZeroB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTimesLhsZeroB.dhall
@@ -1,1 +1,1 @@
-0
+λ(x : Natural) → 0
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTimesNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTimesNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTimesNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTimesNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-1 * x * (1 * y)
+λ(x : Natural) → λ(y : Natural) → 1 * x * (1 * y)
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTimesNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTimesNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTimesNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTimesNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-x * y
+λ(x : Natural) → λ(y : Natural) → x * y
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsOneA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsOneA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsOneA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsOneA.dhall
@@ -1,1 +1,1 @@
-x * 1
+λ(x : Natural) → x * 1
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsOneB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsOneB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsOneB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsOneB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Natural) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsZeroA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsZeroA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsZeroA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsZeroA.dhall
@@ -1,1 +1,1 @@
-x * 0
+λ(x : Natural) → x * 0
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsZeroB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsZeroB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsZeroB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTimesRhsZeroB.dhall
@@ -1,1 +1,1 @@
-0
+λ(x : Natural) → 0
diff --git a/dhall-lang/tests/normalization/success/unit/OptionalBuildFoldFusionA.dhall b/dhall-lang/tests/normalization/success/unit/OptionalBuildFoldFusionA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OptionalBuildFoldFusionA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OptionalBuildFoldFusionA.dhall
@@ -1,1 +1,1 @@
-Optional/build A0 (Optional/fold A1 x)
+λ(T : Type) → λ(x : Optional T) → Optional/build T (Optional/fold T x)
diff --git a/dhall-lang/tests/normalization/success/unit/OptionalBuildFoldFusionB.dhall b/dhall-lang/tests/normalization/success/unit/OptionalBuildFoldFusionB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OptionalBuildFoldFusionB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OptionalBuildFoldFusionB.dhall
@@ -1,1 +1,1 @@
-x
+λ(T : Type) → λ(x : Optional T) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OptionalBuildImplementationA.dhall b/dhall-lang/tests/normalization/success/unit/OptionalBuildImplementationA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OptionalBuildImplementationA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OptionalBuildImplementationA.dhall
@@ -1,3 +1,3 @@
-Optional/build
-A
-(λ(optional : Type) → λ(just : A → optional) → λ(nothing : optional) → x)
+  λ(T : Type)
+→ λ(f : ∀(optional : Type) → (T → optional) → optional → optional)
+→ Optional/build T f
diff --git a/dhall-lang/tests/normalization/success/unit/OptionalBuildImplementationB.dhall b/dhall-lang/tests/normalization/success/unit/OptionalBuildImplementationB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OptionalBuildImplementationB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OptionalBuildImplementationB.dhall
@@ -1,1 +1,3 @@
-x
+  λ(T : Type)
+→ λ(f : ∀(optional : Type) → (T → optional) → optional → optional)
+→ f (Optional T) (λ(a : T) → Some a) (None T)
diff --git a/dhall-lang/tests/normalization/success/unit/OptionalFoldNoneA.dhall b/dhall-lang/tests/normalization/success/unit/OptionalFoldNoneA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OptionalFoldNoneA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OptionalFoldNoneA.dhall
@@ -1,1 +1,1 @@
-Optional/fold A (None A) B (λ(_ : A) → _) x
+λ(T : Type) → λ(x : Bool) → Optional/fold T (None T) Bool (λ(_ : T) → False) x
diff --git a/dhall-lang/tests/normalization/success/unit/OptionalFoldNoneB.dhall b/dhall-lang/tests/normalization/success/unit/OptionalFoldNoneB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OptionalFoldNoneB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OptionalFoldNoneB.dhall
@@ -1,1 +1,1 @@
-x
+λ(T : Type) → λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/OptionalFoldSomeA.dhall b/dhall-lang/tests/normalization/success/unit/OptionalFoldSomeA.dhall
--- a/dhall-lang/tests/normalization/success/unit/OptionalFoldSomeA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OptionalFoldSomeA.dhall
@@ -1,1 +1,4 @@
-Optional/fold A (Some x) B (λ(_ : A) → _) z
+  λ(T : Type)
+→ λ(x : T)
+→ λ(y : Bool)
+→ Optional/fold T (Some x) Bool (λ(_ : T) → False) y
diff --git a/dhall-lang/tests/normalization/success/unit/OptionalFoldSomeB.dhall b/dhall-lang/tests/normalization/success/unit/OptionalFoldSomeB.dhall
--- a/dhall-lang/tests/normalization/success/unit/OptionalFoldSomeB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/OptionalFoldSomeB.dhall
@@ -1,1 +1,1 @@
-x
+λ(T : Type) → λ(x : T) → λ(y : Bool) → False
diff --git a/dhall-lang/tests/normalization/success/unit/RecordA.dhall b/dhall-lang/tests/normalization/success/unit/RecordA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordA.dhall
@@ -1,1 +1,1 @@
-{ a : if True then y else z, b : x }
+λ(x : Bool) → { a = if True then x else x, b = x }
diff --git a/dhall-lang/tests/normalization/success/unit/RecordB.dhall b/dhall-lang/tests/normalization/success/unit/RecordB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordB.dhall
@@ -1,1 +1,1 @@
-{ a : y, b : x }
+λ(x : Bool) → { a = x, b = x }
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionA.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordProjectionA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionA.dhall
@@ -1,1 +1,1 @@
-{ x = a, y = b, z = c }.{ x, z }
+{ x = 1, y = 2, z = 3 }.{ x, z }
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionB.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordProjectionB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionB.dhall
@@ -1,1 +1,1 @@
-{ x = a, z = c }
+{ x = 1, z = 3 }
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeNormalizeProjectionA.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeNormalizeProjectionA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeNormalizeProjectionA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeNormalizeProjectionA.dhall
@@ -1,1 +1,1 @@
-x.({ a : Natural, b : Natural })
+λ(x : { a : Bool, b : Bool, c : Bool }) → x.({ a : Bool, b : Bool })
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeNormalizeProjectionB.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeNormalizeProjectionB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeNormalizeProjectionB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeNormalizeProjectionB.dhall
@@ -1,1 +1,1 @@
-x.{ a, b }
+λ(x : { a : Bool, b : Bool, c : Bool }) → x.{ a, b }
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeWithinFieldSelectionA.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeWithinFieldSelectionA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeWithinFieldSelectionA.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : Bool, b : Bool, c : Bool }) → x.({ a : Bool, b : Bool }).a
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeWithinFieldSelectionB.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeWithinFieldSelectionB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeWithinFieldSelectionB.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : Bool, b : Bool, c : Bool }) → x.a
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordProjectionEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionEmptyA.dhall
@@ -1,1 +1,1 @@
-x.{}
+λ(x : { a : Bool }) → x.{}
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordProjectionEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionEmptyB.dhall
@@ -1,1 +1,1 @@
-{=}
+λ(x : { a : Bool }) → {=}
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordProjectionNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-(if True then y else z).{ x, y }
+λ(x : { a : Bool, b : Bool, c : Bool }) → (if True then x else x).{ a, b }
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordProjectionNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-y.{ x, y }
+λ(x : { a : Bool, b : Bool, c : Bool }) → x.{ a, b }
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionWithinFieldSelectionA.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionWithinFieldSelectionA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionWithinFieldSelectionA.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : Bool, b : Bool, c : Bool }) → x.{ a, b }.a
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionWithinFieldSelectionB.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionWithinFieldSelectionB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionWithinFieldSelectionB.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : Bool, b : Bool, c : Bool }) → x.a
diff --git a/dhall-lang/tests/normalization/success/unit/RecordSelectionA.dhall b/dhall-lang/tests/normalization/success/unit/RecordSelectionA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordSelectionA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordSelectionA.dhall
@@ -1,1 +1,1 @@
-{ x = v }.x
+λ(x : Bool) → { a = x }.a
diff --git a/dhall-lang/tests/normalization/success/unit/RecordSelectionB.dhall b/dhall-lang/tests/normalization/success/unit/RecordSelectionB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordSelectionB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordSelectionB.dhall
@@ -1,1 +1,1 @@
-v
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/RecordSelectionNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/RecordSelectionNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordSelectionNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordSelectionNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-(if True then y else z).x
+λ(x : { a : Bool }) → λ(y : { a : Bool }) → (if True then x else y).a
diff --git a/dhall-lang/tests/normalization/success/unit/RecordSelectionNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/RecordSelectionNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordSelectionNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordSelectionNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-y.x
+λ(x : { a : Bool }) → λ(y : { a : Bool }) → x.a
diff --git a/dhall-lang/tests/normalization/success/unit/RecordTypeA.dhall b/dhall-lang/tests/normalization/success/unit/RecordTypeA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordTypeA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordTypeA.dhall
@@ -1,1 +1,1 @@
-{ a : if True then A else B, b : T }
+let id = λ(X : Type) → X in λ(T : Type) → { a : id Bool, b : T }
diff --git a/dhall-lang/tests/normalization/success/unit/RecordTypeB.dhall b/dhall-lang/tests/normalization/success/unit/RecordTypeB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecordTypeB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecordTypeB.dhall
@@ -1,1 +1,1 @@
-{ a : A, b : T }
+λ(T : Type) → { a : Bool, b : T }
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeLhsEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeLhsEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeLhsEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeLhsEmptyA.dhall
@@ -1,1 +1,1 @@
-{=} ∧ x
+λ(x : { a : Bool }) → {=} ∧ x
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeLhsEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeLhsEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeLhsEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeLhsEmptyB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : { a : Bool }) → x
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNoCollisionA.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNoCollisionA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNoCollisionA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNoCollisionA.dhall
@@ -1,1 +1,1 @@
-{ x = { z = 1 } } ∧ { b = { y = 2 } }
+{ x = { a = 1 } } ∧ { y = { b = 2 } }
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNoCollisionB.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNoCollisionB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNoCollisionB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNoCollisionB.dhall
@@ -1,1 +1,1 @@
-{ b = { y = 2 }, x = { z = 1 } }
+{ x = { a = 1 }, y = { b = 2 } }
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-x ∧ {=} ∧ ({=} ∧ b)
+λ(x : { a : Bool }) → λ(y : { b : Bool }) → x ∧ {=} ∧ ({=} ∧ y)
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-x ∧ b
+λ(x : { a : Bool }) → λ(y : { b : Bool }) → x ∧ y
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeRhsEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeRhsEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeRhsEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeRhsEmptyA.dhall
@@ -1,1 +1,1 @@
-x ∧ {=}
+λ(x : { a : Bool }) → x ∧ {=}
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeRhsEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeRhsEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeRhsEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeRhsEmptyB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : { a : Bool }) → x
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection0A.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection0A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection0A.dhall
@@ -0,0 +1,1 @@
+λ(x : { c : Bool }) → (x ∧ { a = 0, b = 1 }).a
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection0B.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection0B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection0B.dhall
@@ -0,0 +1,1 @@
+λ(x : { c : Bool }) → (x ∧ { a = 0 }).a
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection1A.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection1A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection1A.dhall
@@ -0,0 +1,1 @@
+λ(x : { b : Bool }) → (x ∧ { a = 1 }).b
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection1B.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection1B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection1B.dhall
@@ -0,0 +1,1 @@
+λ(x : { b : Bool }) → x.b
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection2A.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection2A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection2A.dhall
@@ -0,0 +1,1 @@
+λ(x : { b : Bool }) → ({ a = 1 } ∧ x).b
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection2B.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection2B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection2B.dhall
@@ -0,0 +1,1 @@
+λ(x : { b : Bool }) → x.b
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection3A.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection3A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection3A.dhall
@@ -0,0 +1,1 @@
+λ(x : { c : Bool }) → ({ a = 0, b = 1 } ∧ x).a
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection3B.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection3B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection3B.dhall
@@ -0,0 +1,1 @@
+λ(x : { c : Bool }) → ({ a = 0 } ∧ x).a
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeCollisionA.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeCollisionA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeCollisionA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeCollisionA.dhall
@@ -1,1 +1,1 @@
-{ x : { z : A } } ⩓ { x : { y : B } }
+{ x : { z : Bool } } ⩓ { x : { y : Natural } }
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeCollisionB.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeCollisionB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeCollisionB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeCollisionB.dhall
@@ -1,1 +1,1 @@
-{ x : { y : B, z : A } }
+{ x : { y : Natural, z : Bool } }
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeLhsEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeLhsEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeLhsEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeLhsEmptyA.dhall
@@ -1,1 +1,1 @@
-{} ⩓ x
+{} ⩓ { a : Bool }
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeLhsEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeLhsEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeLhsEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeLhsEmptyB.dhall
@@ -1,1 +1,1 @@
-x
+{ a : Bool }
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNoCollisionA.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNoCollisionA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNoCollisionA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNoCollisionA.dhall
@@ -1,1 +1,1 @@
-{ x : { z : A } } ⩓ { b : { y : B } }
+{ x : { a : Bool } } ⩓ { y : { b : Natural } }
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNoCollisionB.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNoCollisionB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNoCollisionB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNoCollisionB.dhall
@@ -1,1 +1,1 @@
-{ b : { y : B }, x : { z : A } }
+{ x : { a : Bool }, y : { b : Natural } }
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-x ⩓ {} ⩓ ({} ⩓ b)
+{ a : Bool } ⩓ {} ⩓ ({} ⩓ { b : Bool })
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-x ⩓ b
+{ a : Bool, b : Bool }
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeRhsEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeRhsEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeRhsEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeRhsEmptyA.dhall
@@ -1,1 +1,1 @@
-x ⩓ {}
+{ a : Bool } ⩓ {}
diff --git a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeRhsEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeRhsEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeRhsEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeRhsEmptyB.dhall
@@ -1,1 +1,1 @@
-x
+{ a : Bool }
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedMergeEquivalentArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeEquivalentArgumentsA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeEquivalentArgumentsA.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : Bool }) → x ⫽ x
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedMergeEquivalentArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeEquivalentArgumentsB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeEquivalentArgumentsB.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : Bool }) → x
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection0A.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection0A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection0A.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : Bool }) → (x ⫽ { a = 0 }).a
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection0B.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection0B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection0B.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : Bool }) → 0
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection1A.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection1A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection1A.dhall
@@ -0,0 +1,1 @@
+λ(x : { b : Bool }) → (x ⫽ { a = 0 }).b
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection1B.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection1B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection1B.dhall
@@ -0,0 +1,1 @@
+λ(x : { b : Bool }) → x.b
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection2A.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection2A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection2A.dhall
@@ -0,0 +1,1 @@
+λ(x : { b : Bool }) → λ(y : Bool) → ({ a = y } ⫽ x).b
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection2B.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection2B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection2B.dhall
@@ -0,0 +1,1 @@
+λ(x : { b : Bool }) → λ(y : Bool) → x.b
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection3A.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection3A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection3A.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : Bool }) → ({ a = 0, b = 1 } ⫽ x).a
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection3B.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection3B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection3B.dhall
@@ -0,0 +1,1 @@
+λ(x : { a : Bool }) → ({ a = 0 } ⫽ x).a
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeLhsEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeLhsEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeLhsEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeLhsEmptyA.dhall
@@ -1,1 +1,1 @@
-{=} ⫽ x
+λ(x : { a : Bool }) → {=} ⫽ x
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeLhsEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeLhsEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeLhsEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeLhsEmptyB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : { a : Bool }) → x
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-x ⫽ {=} ⫽ (y ⫽ {=})
+λ(x : { a : Bool }) → λ(y : { a : Bool }) → x ⫽ {=} ⫽ (y ⫽ {=})
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-x ⫽ y
+λ(x : { a : Bool }) → λ(y : { a : Bool }) → x ⫽ y
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeRhsEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeRhsEmptyA.dhall
--- a/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeRhsEmptyA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeRhsEmptyA.dhall
@@ -1,1 +1,1 @@
-x ⫽ {=}
+λ(x : { a : Bool }) → x ⫽ {=}
diff --git a/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeRhsEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeRhsEmptyB.dhall
--- a/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeRhsEmptyB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeRhsEmptyB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : { a : Bool }) → x
diff --git a/dhall-lang/tests/normalization/success/unit/SomeNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/SomeNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/SomeNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/SomeNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-Some (if True then x else y)
+λ(x : Bool) → λ(y : Bool) → Some (if True then x else y)
diff --git a/dhall-lang/tests/normalization/success/unit/SomeNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/SomeNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/SomeNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/SomeNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-Some x
+λ(x : Bool) → λ(y : Bool) → Some x
diff --git a/dhall-lang/tests/normalization/success/unit/TextInterpolateA.dhall b/dhall-lang/tests/normalization/success/unit/TextInterpolateA.dhall
--- a/dhall-lang/tests/normalization/success/unit/TextInterpolateA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/TextInterpolateA.dhall
@@ -1,1 +1,1 @@
-"s${"b${x}"}"
+λ(x : Text) → "s${"b${x}"}"
diff --git a/dhall-lang/tests/normalization/success/unit/TextInterpolateB.dhall b/dhall-lang/tests/normalization/success/unit/TextInterpolateB.dhall
--- a/dhall-lang/tests/normalization/success/unit/TextInterpolateB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/TextInterpolateB.dhall
@@ -1,1 +1,1 @@
-"sb${x}"
+λ(x : Text) → "sb${x}"
diff --git a/dhall-lang/tests/normalization/success/unit/TextNormalizeInterpolationsA.dhall b/dhall-lang/tests/normalization/success/unit/TextNormalizeInterpolationsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/TextNormalizeInterpolationsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/TextNormalizeInterpolationsA.dhall
@@ -1,1 +1,1 @@
-"s${if True then x else y}"
+λ(x : Text) → λ(y : Text) → "s${if True then x else y}"
diff --git a/dhall-lang/tests/normalization/success/unit/TextNormalizeInterpolationsB.dhall b/dhall-lang/tests/normalization/success/unit/TextNormalizeInterpolationsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/TextNormalizeInterpolationsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/TextNormalizeInterpolationsB.dhall
@@ -1,1 +1,1 @@
-"s${x}"
+λ(x : Text) → λ(y : Text) → "s${x}"
diff --git a/dhall-lang/tests/normalization/success/unit/TextShowInterpolatedA.dhall b/dhall-lang/tests/normalization/success/unit/TextShowInterpolatedA.dhall
--- a/dhall-lang/tests/normalization/success/unit/TextShowInterpolatedA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/TextShowInterpolatedA.dhall
@@ -1,1 +1,1 @@
-Text/show "text ${with} interpolation"
+λ(with : Text) → Text/show "text ${with} interpolation"
diff --git a/dhall-lang/tests/normalization/success/unit/TextShowInterpolatedB.dhall b/dhall-lang/tests/normalization/success/unit/TextShowInterpolatedB.dhall
--- a/dhall-lang/tests/normalization/success/unit/TextShowInterpolatedB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/TextShowInterpolatedB.dhall
@@ -1,1 +1,1 @@
-Text/show "text ${with} interpolation"
+λ(with : Text) → Text/show "text ${with} interpolation"
diff --git a/dhall-lang/tests/normalization/success/unit/TypeAnnotationA.dhall b/dhall-lang/tests/normalization/success/unit/TypeAnnotationA.dhall
--- a/dhall-lang/tests/normalization/success/unit/TypeAnnotationA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/TypeAnnotationA.dhall
@@ -1,1 +1,1 @@
-x : A
+λ(x : Bool) → x : Bool
diff --git a/dhall-lang/tests/normalization/success/unit/TypeAnnotationB.dhall b/dhall-lang/tests/normalization/success/unit/TypeAnnotationB.dhall
--- a/dhall-lang/tests/normalization/success/unit/TypeAnnotationB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/TypeAnnotationB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeAlternativesA.dhall b/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeAlternativesA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeAlternativesA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x = y | y : if True then X else Y | z >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeAlternativesB.dhall b/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeAlternativesB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeAlternativesB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x = y | y : X | z >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeArgumentsA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeArgumentsA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x = if True then y else z >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeArgumentsB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeArgumentsB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x = y >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionLiteralSortAlternativesA.dhall b/dhall-lang/tests/normalization/success/unit/UnionLiteralSortAlternativesA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/UnionLiteralSortAlternativesA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x = y | z | y : B >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionLiteralSortAlternativesB.dhall b/dhall-lang/tests/normalization/success/unit/UnionLiteralSortAlternativesB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/UnionLiteralSortAlternativesB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x = y | y : B | z >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionProjectConstructorA.dhall b/dhall-lang/tests/normalization/success/unit/UnionProjectConstructorA.dhall
--- a/dhall-lang/tests/normalization/success/unit/UnionProjectConstructorA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/UnionProjectConstructorA.dhall
@@ -1,1 +1,1 @@
-< x : T >.x
+< x : Bool >.x
diff --git a/dhall-lang/tests/normalization/success/unit/UnionProjectConstructorB.dhall b/dhall-lang/tests/normalization/success/unit/UnionProjectConstructorB.dhall
--- a/dhall-lang/tests/normalization/success/unit/UnionProjectConstructorB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/UnionProjectConstructorB.dhall
@@ -1,1 +1,1 @@
-< x : T >.x
+< x : Bool >.x
diff --git a/dhall-lang/tests/normalization/success/unit/UnionTypeA.dhall b/dhall-lang/tests/normalization/success/unit/UnionTypeA.dhall
--- a/dhall-lang/tests/normalization/success/unit/UnionTypeA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/UnionTypeA.dhall
@@ -1,1 +1,1 @@
-< x : B | z >
+< x : Bool | z >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionTypeB.dhall b/dhall-lang/tests/normalization/success/unit/UnionTypeB.dhall
--- a/dhall-lang/tests/normalization/success/unit/UnionTypeB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/UnionTypeB.dhall
@@ -1,1 +1,1 @@
-< x : B | z >
+< x : Bool | z >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionTypeNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/UnionTypeNormalizeArgumentsA.dhall
--- a/dhall-lang/tests/normalization/success/unit/UnionTypeNormalizeArgumentsA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/UnionTypeNormalizeArgumentsA.dhall
@@ -1,1 +1,1 @@
-< x : if True then B else Z | z >
+let id = λ(X : Type) → X in < x : id Bool | z >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionTypeNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/UnionTypeNormalizeArgumentsB.dhall
--- a/dhall-lang/tests/normalization/success/unit/UnionTypeNormalizeArgumentsB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/UnionTypeNormalizeArgumentsB.dhall
@@ -1,1 +1,1 @@
-< x : B | z >
+< x : Bool | z >
diff --git a/dhall-lang/tests/normalization/success/unit/VariableA.dhall b/dhall-lang/tests/normalization/success/unit/VariableA.dhall
--- a/dhall-lang/tests/normalization/success/unit/VariableA.dhall
+++ b/dhall-lang/tests/normalization/success/unit/VariableA.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/normalization/success/unit/VariableB.dhall b/dhall-lang/tests/normalization/success/unit/VariableB.dhall
--- a/dhall-lang/tests/normalization/success/unit/VariableB.dhall
+++ b/dhall-lang/tests/normalization/success/unit/VariableB.dhall
@@ -1,1 +1,1 @@
-x
+λ(x : Bool) → x
diff --git a/dhall-lang/tests/parser/failure/ImportHeadersExteriorHash.dhall b/dhall-lang/tests/parser/failure/ImportHeadersExteriorHash.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/failure/ImportHeadersExteriorHash.dhall
@@ -0,0 +1,1 @@
+(https://example.com/foo using ./headers) sha256:0000000000000000000000000000000000000000000000000000000000000000
diff --git a/dhall-lang/tests/parser/failure/ProjectionByTypeNeedsParens.dhall b/dhall-lang/tests/parser/failure/ProjectionByTypeNeedsParens.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/failure/ProjectionByTypeNeedsParens.dhall
@@ -0,0 +1,1 @@
+r.{ x: T }
diff --git a/dhall-lang/tests/parser/failure/missingSpace.dhall b/dhall-lang/tests/parser/failure/missingSpace.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/failure/missingSpace.dhall
+++ /dev/null
@@ -1,2 +0,0 @@
--- There needs to be a space between a function and its argument
-./example.dhall[1]
diff --git a/dhall-lang/tests/parser/success/doubleA.dhall b/dhall-lang/tests/parser/success/doubleA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/doubleA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-[ 1.1, -1.1, 1e1, 1.1e1, NaN, Infinity, -Infinity, 0.0 ]
diff --git a/dhall-lang/tests/parser/success/doubleB.dhallb b/dhall-lang/tests/parser/success/doubleB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/doubleB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/ifThenElseA.dhall b/dhall-lang/tests/parser/success/ifThenElseA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/ifThenElseA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-if True then 1 else 2
diff --git a/dhall-lang/tests/parser/success/ifThenElseB.dhallb b/dhall-lang/tests/parser/success/ifThenElseB.dhallb
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/ifThenElseB.dhallb
+++ /dev/null
@@ -1,1 +0,0 @@
-õ
diff --git a/dhall-lang/tests/parser/success/letA.dhall b/dhall-lang/tests/parser/success/letA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/letA.dhall
+++ /dev/null
@@ -1,3 +0,0 @@
-    let x = 1
-in  let y : Natural = 2
-in  x
diff --git a/dhall-lang/tests/parser/success/letB.dhallb b/dhall-lang/tests/parser/success/letB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/letB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/multiletA.dhall b/dhall-lang/tests/parser/success/multiletA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/multiletA.dhall
+++ /dev/null
@@ -1,3 +0,0 @@
-let a = 1
-let b = 2
-in  a + b
diff --git a/dhall-lang/tests/parser/success/multiletB.dhallb b/dhall-lang/tests/parser/success/multiletB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/multiletB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/unionA.dhall b/dhall-lang/tests/parser/success/unionA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/unionA.dhall
+++ /dev/null
@@ -1,4 +0,0 @@
-< A : {   }
-| B = { = }
-| C : {}
-> : < A : {} | B : {} | C : {} >
diff --git a/dhall-lang/tests/parser/success/unionB.dhallb b/dhall-lang/tests/parser/success/unionB.dhallb
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/unionB.dhallb
+++ /dev/null
@@ -1,1 +0,0 @@
-aB ¢aA aC £aA aB aC 
diff --git a/dhall-lang/tests/parser/success/unit/AnnotationA.dhall b/dhall-lang/tests/parser/success/unit/AnnotationA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/AnnotationA.dhall
@@ -0,0 +1,1 @@
+x : T
diff --git a/dhall-lang/tests/parser/success/unit/AnnotationB.dhallb b/dhall-lang/tests/parser/success/unit/AnnotationB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/AnnotationB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/AssertA.dhall b/dhall-lang/tests/parser/success/unit/AssertA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/AssertA.dhall
@@ -0,0 +1,1 @@
+assert : T
diff --git a/dhall-lang/tests/parser/success/unit/AssertB.dhallb b/dhall-lang/tests/parser/success/unit/AssertB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/AssertB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/AssertEquivalenceA.dhall b/dhall-lang/tests/parser/success/unit/AssertEquivalenceA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/AssertEquivalenceA.dhall
@@ -0,0 +1,1 @@
+assert : x === y
diff --git a/dhall-lang/tests/parser/success/unit/AssertEquivalenceB.dhallb b/dhall-lang/tests/parser/success/unit/AssertEquivalenceB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/AssertEquivalenceB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/AssertEquivalenceUnicodeA.dhall b/dhall-lang/tests/parser/success/unit/AssertEquivalenceUnicodeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/AssertEquivalenceUnicodeA.dhall
@@ -0,0 +1,1 @@
+assert : x ≡ y
diff --git a/dhall-lang/tests/parser/success/unit/AssertEquivalenceUnicodeB.dhallb b/dhall-lang/tests/parser/success/unit/AssertEquivalenceUnicodeB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/AssertEquivalenceUnicodeB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/AssertPrecedenceA.dhall b/dhall-lang/tests/parser/success/unit/AssertPrecedenceA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/AssertPrecedenceA.dhall
@@ -0,0 +1,1 @@
+assert : T U
diff --git a/dhall-lang/tests/parser/success/unit/AssertPrecedenceB.dhallb b/dhall-lang/tests/parser/success/unit/AssertPrecedenceB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/AssertPrecedenceB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/BuiltinListBuildA.dhall b/dhall-lang/tests/parser/success/unit/BuiltinListBuildA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/BuiltinListBuildA.dhall
@@ -0,0 +1,1 @@
+List/Build
diff --git a/dhall-lang/tests/parser/success/unit/BuiltinListBuildB.dhallb b/dhall-lang/tests/parser/success/unit/BuiltinListBuildB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/BuiltinListBuildB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitExponentA.dhall b/dhall-lang/tests/parser/success/unit/DoubleLitExponentA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/DoubleLitExponentA.dhall
@@ -0,0 +1,1 @@
+1.23e4
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitExponentB.dhallb b/dhall-lang/tests/parser/success/unit/DoubleLitExponentB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/DoubleLitExponentB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitExponentNegativeA.dhall b/dhall-lang/tests/parser/success/unit/DoubleLitExponentNegativeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/DoubleLitExponentNegativeA.dhall
@@ -0,0 +1,1 @@
+1.23e-4
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitExponentNegativeB.dhallb b/dhall-lang/tests/parser/success/unit/DoubleLitExponentNegativeB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/DoubleLitExponentNegativeB.dhallb
@@ -0,0 +1,1 @@
+û? 1ônÒF
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitExponentNoDotA.dhall b/dhall-lang/tests/parser/success/unit/DoubleLitExponentNoDotA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/DoubleLitExponentNoDotA.dhall
@@ -0,0 +1,1 @@
+1e4
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitExponentNoDotB.dhallb b/dhall-lang/tests/parser/success/unit/DoubleLitExponentNoDotB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/DoubleLitExponentNoDotB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitInfinityA.dhall b/dhall-lang/tests/parser/success/unit/DoubleLitInfinityA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/DoubleLitInfinityA.dhall
@@ -0,0 +1,1 @@
+Infinity
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitInfinityB.dhallb b/dhall-lang/tests/parser/success/unit/DoubleLitInfinityB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/DoubleLitInfinityB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitNaNA.dhall b/dhall-lang/tests/parser/success/unit/DoubleLitNaNA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/DoubleLitNaNA.dhall
@@ -0,0 +1,1 @@
+NaN
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitNaNB.dhallb b/dhall-lang/tests/parser/success/unit/DoubleLitNaNB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/DoubleLitNaNB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitNegInfinityA.dhall b/dhall-lang/tests/parser/success/unit/DoubleLitNegInfinityA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/DoubleLitNegInfinityA.dhall
@@ -0,0 +1,1 @@
+-Infinity
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitNegInfinityB.dhallb b/dhall-lang/tests/parser/success/unit/DoubleLitNegInfinityB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/DoubleLitNegInfinityB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitNegativeA.dhall b/dhall-lang/tests/parser/success/unit/DoubleLitNegativeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/DoubleLitNegativeA.dhall
@@ -0,0 +1,1 @@
+-1.23
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitNegativeB.dhallb b/dhall-lang/tests/parser/success/unit/DoubleLitNegativeB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/DoubleLitNegativeB.dhallb
@@ -0,0 +1,1 @@
+û¿ó®záG®
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitPositiveA.dhall b/dhall-lang/tests/parser/success/unit/DoubleLitPositiveA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/DoubleLitPositiveA.dhall
@@ -0,0 +1,1 @@
+1.23
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitPositiveB.dhallb b/dhall-lang/tests/parser/success/unit/DoubleLitPositiveB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/DoubleLitPositiveB.dhallb
@@ -0,0 +1,1 @@
+û?ó®záG®
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitSecretelyIntA.dhall b/dhall-lang/tests/parser/success/unit/DoubleLitSecretelyIntA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/DoubleLitSecretelyIntA.dhall
@@ -0,0 +1,5 @@
+{-
+    Some languages do not make principled distinctions between number types, so
+    this checks that this Double is not silently considered as a Natural
+-}
+1.0
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitSecretelyIntB.dhallb b/dhall-lang/tests/parser/success/unit/DoubleLitSecretelyIntB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/DoubleLitSecretelyIntB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitZeroA.dhall b/dhall-lang/tests/parser/success/unit/DoubleLitZeroA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/DoubleLitZeroA.dhall
@@ -0,0 +1,1 @@
+0.0
diff --git a/dhall-lang/tests/parser/success/unit/DoubleLitZeroB.dhallb b/dhall-lang/tests/parser/success/unit/DoubleLitZeroB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/DoubleLitZeroB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/FieldA.dhall b/dhall-lang/tests/parser/success/unit/FieldA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/FieldA.dhall
@@ -0,0 +1,1 @@
+r.x
diff --git a/dhall-lang/tests/parser/success/unit/FieldB.dhallb b/dhall-lang/tests/parser/success/unit/FieldB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/FieldB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/FieldBuiltinNameA.dhall b/dhall-lang/tests/parser/success/unit/FieldBuiltinNameA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/FieldBuiltinNameA.dhall
@@ -0,0 +1,1 @@
+r.List
diff --git a/dhall-lang/tests/parser/success/unit/FieldBuiltinNameB.dhallb b/dhall-lang/tests/parser/success/unit/FieldBuiltinNameB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/FieldBuiltinNameB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/FieldQuotedA.dhall b/dhall-lang/tests/parser/success/unit/FieldQuotedA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/FieldQuotedA.dhall
@@ -0,0 +1,1 @@
+r.`x`
diff --git a/dhall-lang/tests/parser/success/unit/FieldQuotedB.dhallb b/dhall-lang/tests/parser/success/unit/FieldQuotedB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/FieldQuotedB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/FunctionApplicationMultipleArgsA.dhall b/dhall-lang/tests/parser/success/unit/FunctionApplicationMultipleArgsA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/FunctionApplicationMultipleArgsA.dhall
@@ -0,0 +1,1 @@
+f x y z
diff --git a/dhall-lang/tests/parser/success/unit/FunctionApplicationMultipleArgsB.dhallb b/dhall-lang/tests/parser/success/unit/FunctionApplicationMultipleArgsB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/FunctionApplicationMultipleArgsB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/FunctionApplicationOneArgA.dhall b/dhall-lang/tests/parser/success/unit/FunctionApplicationOneArgA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/FunctionApplicationOneArgA.dhall
@@ -0,0 +1,1 @@
+f x
diff --git a/dhall-lang/tests/parser/success/unit/FunctionApplicationOneArgB.dhallb b/dhall-lang/tests/parser/success/unit/FunctionApplicationOneArgB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/FunctionApplicationOneArgB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/FunctionTypeArrowA.dhall b/dhall-lang/tests/parser/success/unit/FunctionTypeArrowA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/FunctionTypeArrowA.dhall
@@ -0,0 +1,1 @@
+T -> U
diff --git a/dhall-lang/tests/parser/success/unit/FunctionTypeArrowB.dhallb b/dhall-lang/tests/parser/success/unit/FunctionTypeArrowB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/FunctionTypeArrowB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/FunctionTypePiA.dhall b/dhall-lang/tests/parser/success/unit/FunctionTypePiA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/FunctionTypePiA.dhall
@@ -0,0 +1,1 @@
+forall(x: T) -> U
diff --git a/dhall-lang/tests/parser/success/unit/FunctionTypePiB.dhallb b/dhall-lang/tests/parser/success/unit/FunctionTypePiB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/FunctionTypePiB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/FunctionTypePiNestedA.dhall b/dhall-lang/tests/parser/success/unit/FunctionTypePiNestedA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/FunctionTypePiNestedA.dhall
@@ -0,0 +1,1 @@
+forall(x: T) -> ∀(y: U) -> V
diff --git a/dhall-lang/tests/parser/success/unit/FunctionTypePiNestedB.dhallb b/dhall-lang/tests/parser/success/unit/FunctionTypePiNestedB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/FunctionTypePiNestedB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/FunctionTypePiUnderscoreA.dhall b/dhall-lang/tests/parser/success/unit/FunctionTypePiUnderscoreA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/FunctionTypePiUnderscoreA.dhall
@@ -0,0 +1,1 @@
+forall(_: T) -> U
diff --git a/dhall-lang/tests/parser/success/unit/FunctionTypePiUnderscoreB.dhallb b/dhall-lang/tests/parser/success/unit/FunctionTypePiUnderscoreB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/FunctionTypePiUnderscoreB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/FunctionTypePiUnicodeA.dhall b/dhall-lang/tests/parser/success/unit/FunctionTypePiUnicodeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/FunctionTypePiUnicodeA.dhall
@@ -0,0 +1,1 @@
+∀(x: T) -> U
diff --git a/dhall-lang/tests/parser/success/unit/FunctionTypePiUnicodeB.dhallb b/dhall-lang/tests/parser/success/unit/FunctionTypePiUnicodeB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/FunctionTypePiUnicodeB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/LambdaUnicodeA.dhall b/dhall-lang/tests/parser/success/unit/LambdaUnicodeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/LambdaUnicodeA.dhall
@@ -0,0 +1,1 @@
+λ(x : T) -> y
diff --git a/dhall-lang/tests/parser/success/unit/LambdaUnicodeB.dhallb b/dhall-lang/tests/parser/success/unit/LambdaUnicodeB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/LambdaUnicodeB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/LetA.dhall b/dhall-lang/tests/parser/success/unit/LetA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/LetA.dhall
@@ -0,0 +1,1 @@
+let x: T = v in e
diff --git a/dhall-lang/tests/parser/success/unit/LetB.dhallb b/dhall-lang/tests/parser/success/unit/LetB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/LetB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/LetMultiA.dhall b/dhall-lang/tests/parser/success/unit/LetMultiA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/LetMultiA.dhall
@@ -0,0 +1,1 @@
+let x: T = v let y: U = w in e
diff --git a/dhall-lang/tests/parser/success/unit/LetMultiB.dhallb b/dhall-lang/tests/parser/success/unit/LetMultiB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/LetMultiB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/LetNestedA.dhall b/dhall-lang/tests/parser/success/unit/LetNestedA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/LetNestedA.dhall
@@ -0,0 +1,1 @@
+let x: T = v in let y: U = w in e
diff --git a/dhall-lang/tests/parser/success/unit/LetNestedB.dhallb b/dhall-lang/tests/parser/success/unit/LetNestedB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/LetNestedB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/ListLitNonEmptyA.dhall b/dhall-lang/tests/parser/success/unit/ListLitNonEmptyA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/ListLitNonEmptyA.dhall
@@ -0,0 +1,1 @@
+[x, y]
diff --git a/dhall-lang/tests/parser/success/unit/ListLitNonEmptyAnnotatedA.dhall b/dhall-lang/tests/parser/success/unit/ListLitNonEmptyAnnotatedA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/ListLitNonEmptyAnnotatedA.dhall
@@ -0,0 +1,1 @@
+[x, y] : List T
diff --git a/dhall-lang/tests/parser/success/unit/ListLitNonEmptyAnnotatedB.dhallb b/dhall-lang/tests/parser/success/unit/ListLitNonEmptyAnnotatedB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/ListLitNonEmptyAnnotatedB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/ListLitNonEmptyB.dhallb b/dhall-lang/tests/parser/success/unit/ListLitNonEmptyB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/ListLitNonEmptyB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/ProjectionA.dhall b/dhall-lang/tests/parser/success/unit/ProjectionA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/ProjectionA.dhall
@@ -0,0 +1,1 @@
+r.{x, y, z}
diff --git a/dhall-lang/tests/parser/success/unit/ProjectionB.dhallb b/dhall-lang/tests/parser/success/unit/ProjectionB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/ProjectionB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/RecordLitA.dhall b/dhall-lang/tests/parser/success/unit/RecordLitA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/RecordLitA.dhall
@@ -0,0 +1,1 @@
+{ x = 1, y = 2 }
diff --git a/dhall-lang/tests/parser/success/unit/RecordLitB.dhallb b/dhall-lang/tests/parser/success/unit/RecordLitB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/RecordLitB.dhallb
@@ -0,0 +1,1 @@
+¢axay
diff --git a/dhall-lang/tests/parser/success/unit/RecordTypeA.dhall b/dhall-lang/tests/parser/success/unit/RecordTypeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/RecordTypeA.dhall
@@ -0,0 +1,1 @@
+{ x: T, y: U }
diff --git a/dhall-lang/tests/parser/success/unit/RecordTypeB.dhallb b/dhall-lang/tests/parser/success/unit/RecordTypeB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/RecordTypeB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/UnionLit1A.dhall b/dhall-lang/tests/parser/success/unit/UnionLit1A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/unit/UnionLit1A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x = t | y: T | z | w: T >
diff --git a/dhall-lang/tests/parser/success/unit/UnionLit1B.dhallb b/dhall-lang/tests/parser/success/unit/UnionLit1B.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/unit/UnionLit1B.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/unit/UnionLit2A.dhall b/dhall-lang/tests/parser/success/unit/UnionLit2A.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/unit/UnionLit2A.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x: T | y = t | z | w: T >
diff --git a/dhall-lang/tests/parser/success/unit/UnionLit2B.dhallb b/dhall-lang/tests/parser/success/unit/UnionLit2B.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/unit/UnionLit2B.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/unit/ifThenElseA.dhall b/dhall-lang/tests/parser/success/unit/ifThenElseA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/ifThenElseA.dhall
@@ -0,0 +1,1 @@
+if True then 1 else 2
diff --git a/dhall-lang/tests/parser/success/unit/ifThenElseB.dhallb b/dhall-lang/tests/parser/success/unit/ifThenElseB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/ifThenElseB.dhallb
@@ -0,0 +1,1 @@
+õ
diff --git a/dhall-lang/tests/parser/success/unit/import/AsLocationAbsoluteA.dhall b/dhall-lang/tests/parser/success/unit/import/AsLocationAbsoluteA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/AsLocationAbsoluteA.dhall
@@ -0,0 +1,1 @@
+/absolute/import as Location
diff --git a/dhall-lang/tests/parser/success/unit/import/AsLocationAbsoluteB.dhallb b/dhall-lang/tests/parser/success/unit/import/AsLocationAbsoluteB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/AsLocationAbsoluteB.dhallb
@@ -0,0 +1,1 @@
+öhabsolutefimport
diff --git a/dhall-lang/tests/parser/success/unit/import/AsLocationEnvA.dhall b/dhall-lang/tests/parser/success/unit/import/AsLocationEnvA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/AsLocationEnvA.dhall
@@ -0,0 +1,1 @@
+env:HOME as Location
diff --git a/dhall-lang/tests/parser/success/unit/import/AsLocationEnvB.dhallb b/dhall-lang/tests/parser/success/unit/import/AsLocationEnvB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/AsLocationEnvB.dhallb
@@ -0,0 +1,1 @@
+ödHOME
diff --git a/dhall-lang/tests/parser/success/unit/import/AsLocationHashA.dhall b/dhall-lang/tests/parser/success/unit/import/AsLocationHashA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/AsLocationHashA.dhall
@@ -0,0 +1,1 @@
+./some/import sha256:0000000000000000000000000000000000000000000000000000000000000000 as Location
diff --git a/dhall-lang/tests/parser/success/unit/import/AsLocationHashB.dhallb b/dhall-lang/tests/parser/success/unit/import/AsLocationHashB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/AsLocationHashB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/AsLocationLocalA.dhall b/dhall-lang/tests/parser/success/unit/import/AsLocationLocalA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/AsLocationLocalA.dhall
@@ -0,0 +1,1 @@
+./local/import as Location
diff --git a/dhall-lang/tests/parser/success/unit/import/AsLocationLocalB.dhallb b/dhall-lang/tests/parser/success/unit/import/AsLocationLocalB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/AsLocationLocalB.dhallb
@@ -0,0 +1,1 @@
+öelocalfimport
diff --git a/dhall-lang/tests/parser/success/unit/import/AsLocationMissingA.dhall b/dhall-lang/tests/parser/success/unit/import/AsLocationMissingA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/AsLocationMissingA.dhall
@@ -0,0 +1,1 @@
+missing as Location
diff --git a/dhall-lang/tests/parser/success/unit/import/AsLocationMissingB.dhallb b/dhall-lang/tests/parser/success/unit/import/AsLocationMissingB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/AsLocationMissingB.dhallb
@@ -0,0 +1,1 @@
+ö
diff --git a/dhall-lang/tests/parser/success/unit/import/AsLocationRemoteA.dhall b/dhall-lang/tests/parser/success/unit/import/AsLocationRemoteA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/AsLocationRemoteA.dhall
@@ -0,0 +1,1 @@
+https://prelude.dhall-lang.org/package.dhall as Location
diff --git a/dhall-lang/tests/parser/success/unit/import/AsLocationRemoteB.dhallb b/dhall-lang/tests/parser/success/unit/import/AsLocationRemoteB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/AsLocationRemoteB.dhallb
@@ -0,0 +1,1 @@
+öövprelude.dhall-lang.orgmpackage.dhallö
diff --git a/dhall-lang/tests/parser/success/unit/import/HeadersA.dhall b/dhall-lang/tests/parser/success/unit/import/HeadersA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/HeadersA.dhall
@@ -0,0 +1,1 @@
+https://example.com/foo using x
diff --git a/dhall-lang/tests/parser/success/unit/import/HeadersB.dhallb b/dhall-lang/tests/parser/success/unit/import/HeadersB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/HeadersB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashA.dhall b/dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashA.dhall
@@ -0,0 +1,1 @@
+https://example.com/foo using (./headers sha256:0000000000000000000000000000000000000000000000000000000000000000) sha256:1111111111111111111111111111111111111111111111111111111111111111
diff --git a/dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashB.dhallb b/dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashPrecedenceA.dhall b/dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashPrecedenceA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashPrecedenceA.dhall
@@ -0,0 +1,1 @@
+https://example.com/foo using ./headers sha256:0000000000000000000000000000000000000000000000000000000000000000 sha256:1111111111111111111111111111111111111111111111111111111111111111
diff --git a/dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashPrecedenceB.dhallb b/dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashPrecedenceB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashPrecedenceB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/HeadersHashPrecedenceA.dhall b/dhall-lang/tests/parser/success/unit/import/HeadersHashPrecedenceA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/HeadersHashPrecedenceA.dhall
@@ -0,0 +1,1 @@
+https://example.com/foo using ./headers sha256:0000000000000000000000000000000000000000000000000000000000000000
diff --git a/dhall-lang/tests/parser/success/unit/import/HeadersHashPrecedenceB.dhallb b/dhall-lang/tests/parser/success/unit/import/HeadersHashPrecedenceB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/HeadersHashPrecedenceB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/HeadersInteriorHashA.dhall b/dhall-lang/tests/parser/success/unit/import/HeadersInteriorHashA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/HeadersInteriorHashA.dhall
@@ -0,0 +1,1 @@
+https://example.com/foo using (./headers sha256:0000000000000000000000000000000000000000000000000000000000000000)
diff --git a/dhall-lang/tests/parser/success/unit/import/HeadersInteriorHashB.dhallb b/dhall-lang/tests/parser/success/unit/import/HeadersInteriorHashB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/HeadersInteriorHashB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/ImportAsNoSpaceA.dhall b/dhall-lang/tests/parser/success/unit/import/ImportAsNoSpaceA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/ImportAsNoSpaceA.dhall
@@ -0,0 +1,1 @@
+./import asText
diff --git a/dhall-lang/tests/parser/success/unit/import/ImportAsNoSpaceB.dhallb b/dhall-lang/tests/parser/success/unit/import/ImportAsNoSpaceB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/ImportAsNoSpaceB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/MissingA.dhall b/dhall-lang/tests/parser/success/unit/import/MissingA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/MissingA.dhall
@@ -0,0 +1,1 @@
+missing
diff --git a/dhall-lang/tests/parser/success/unit/import/MissingB.dhallb b/dhall-lang/tests/parser/success/unit/import/MissingB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/MissingB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/asLocationA.dhall b/dhall-lang/tests/parser/success/unit/import/asLocationA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/unit/import/asLocationA.dhall
+++ /dev/null
@@ -1,6 +0,0 @@
-{ _1 = ./some/import.dhall as Location
-, _2 = /absolute/import sha256:f9340badf94a684e652e0a384f64363293d8b632d971f3453f7ee22f10ab6e75 as Location
-, _3 = https://prelude.dhall-lang.org/package.dhall as Location
-, _4 = env:HOME as Location
-, _5 = missing as Location
-}
diff --git a/dhall-lang/tests/parser/success/unit/import/asLocationB.dhallb b/dhall-lang/tests/parser/success/unit/import/asLocationB.dhallb
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/unit/import/asLocationB.dhallb
+++ /dev/null
@@ -1,2 +0,0 @@
-¥b_1ödsomelimport.dhallb_2X" ù4­ùJhNe.
-8Od62Ø¶2ÙqóE?~â/«nuhabsolutefimportb_3öövprelude.dhall-lang.orgmpackage.dhallöb_4ödHOMEb_5ö
diff --git a/dhall-lang/tests/parser/success/unit/import/parenthesizeUsingA.dhall b/dhall-lang/tests/parser/success/unit/import/parenthesizeUsingA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/unit/import/parenthesizeUsingA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate using (./a.dhall sha256:16173e984d35ee3ffd8b6b79167df89480e67d1cd03ea5d0fc93689e4d928e61) sha256:b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ad
diff --git a/dhall-lang/tests/parser/success/unit/import/parenthesizeUsingB.dhallb b/dhall-lang/tests/parser/success/unit/import/parenthesizeUsingB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/unit/import/parenthesizeUsingB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/unit/import/pathTerminationUnionA.dhall b/dhall-lang/tests/parser/success/unit/import/pathTerminationUnionA.dhall
--- a/dhall-lang/tests/parser/success/unit/import/pathTerminationUnionA.dhall
+++ b/dhall-lang/tests/parser/success/unit/import/pathTerminationUnionA.dhall
@@ -1,2 +1,2 @@
 -- Verify that certain punctuation marks terminate paths correctly
-<foo = ./example| bar: ./example>
+<foo: ./example| bar: ./example>
diff --git a/dhall-lang/tests/parser/success/unit/import/pathTerminationUnionB.dhallb b/dhall-lang/tests/parser/success/unit/import/pathTerminationUnionB.dhallb
Binary files a/dhall-lang/tests/parser/success/unit/import/pathTerminationUnionB.dhallb and b/dhall-lang/tests/parser/success/unit/import/pathTerminationUnionB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/quotedPathsB.dhallb b/dhall-lang/tests/parser/success/unit/import/quotedPathsB.dhallb
Binary files a/dhall-lang/tests/parser/success/unit/import/quotedPathsB.dhallb and b/dhall-lang/tests/parser/success/unit/import/quotedPathsB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/urls/escapedPathA.dhall b/dhall-lang/tests/parser/success/unit/import/urls/escapedPathA.dhall
--- a/dhall-lang/tests/parser/success/unit/import/urls/escapedPathA.dhall
+++ b/dhall-lang/tests/parser/success/unit/import/urls/escapedPathA.dhall
@@ -1,1 +1,1 @@
-https://example.com/a%20b/c%2fd/e+f
+https://example.com/a%20b/c%2fd/e+f/g%2dh
diff --git a/dhall-lang/tests/parser/success/unit/import/urls/escapedPathB.dhallb b/dhall-lang/tests/parser/success/unit/import/urls/escapedPathB.dhallb
Binary files a/dhall-lang/tests/parser/success/unit/import/urls/escapedPathB.dhallb and b/dhall-lang/tests/parser/success/unit/import/urls/escapedPathB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/urls/escapedQueryA.dhall b/dhall-lang/tests/parser/success/unit/import/urls/escapedQueryA.dhall
--- a/dhall-lang/tests/parser/success/unit/import/urls/escapedQueryA.dhall
+++ b/dhall-lang/tests/parser/success/unit/import/urls/escapedQueryA.dhall
@@ -1,2 +1,1 @@
--- Unlike paths, query strings should *not* be decoded
 https://example.com/foo?a%20b=c%2fd&e+f/?
diff --git a/dhall-lang/tests/parser/success/unit/import/urls/quotedPathFakeUrlEncodeB.dhallb b/dhall-lang/tests/parser/success/unit/import/urls/quotedPathFakeUrlEncodeB.dhallb
Binary files a/dhall-lang/tests/parser/success/unit/import/urls/quotedPathFakeUrlEncodeB.dhallb and b/dhall-lang/tests/parser/success/unit/import/urls/quotedPathFakeUrlEncodeB.dhallb differ
diff --git a/dhall-lang/tests/type-inference/success/simple/RecordTypeMixedKinds2A.dhall b/dhall-lang/tests/type-inference/success/simple/RecordTypeMixedKinds2A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/simple/RecordTypeMixedKinds2A.dhall
@@ -0,0 +1,1 @@
+{ x : Kind, y : Type }
diff --git a/dhall-lang/tests/type-inference/success/simple/RecordTypeMixedKinds2B.dhall b/dhall-lang/tests/type-inference/success/simple/RecordTypeMixedKinds2B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/simple/RecordTypeMixedKinds2B.dhall
@@ -0,0 +1,1 @@
+Sort
diff --git a/dhall-lang/tests/type-inference/success/simple/RecordTypeMixedKinds3A.dhall b/dhall-lang/tests/type-inference/success/simple/RecordTypeMixedKinds3A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/simple/RecordTypeMixedKinds3A.dhall
@@ -0,0 +1,1 @@
+{ x : Kind, y : Bool }
diff --git a/dhall-lang/tests/type-inference/success/simple/RecordTypeMixedKinds3B.dhall b/dhall-lang/tests/type-inference/success/simple/RecordTypeMixedKinds3B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/simple/RecordTypeMixedKinds3B.dhall
@@ -0,0 +1,1 @@
+Sort
diff --git a/dhall-lang/tests/type-inference/success/simple/alternativesAreTypesA.dhall b/dhall-lang/tests/type-inference/success/simple/alternativesAreTypesA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/type-inference/success/simple/alternativesAreTypesA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< Left = List | Right : Type >
diff --git a/dhall-lang/tests/type-inference/success/simple/alternativesAreTypesB.dhall b/dhall-lang/tests/type-inference/success/simple/alternativesAreTypesB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/type-inference/success/simple/alternativesAreTypesB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< Left : Type → Type | Right : Type >
diff --git a/dhall-lang/tests/type-inference/success/unit/AssertAlphaA.dhall b/dhall-lang/tests/type-inference/success/unit/AssertAlphaA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/AssertAlphaA.dhall
@@ -0,0 +1,1 @@
+assert : (\(x: Bool) -> x) === (\(y: Bool) -> y)
diff --git a/dhall-lang/tests/type-inference/success/unit/AssertAlphaB.dhall b/dhall-lang/tests/type-inference/success/unit/AssertAlphaB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/AssertAlphaB.dhall
@@ -0,0 +1,1 @@
+(λ(x : Bool) → x) ≡ (λ(y : Bool) → y)
diff --git a/dhall-lang/tests/type-inference/success/unit/AssertNaNA.dhall b/dhall-lang/tests/type-inference/success/unit/AssertNaNA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/AssertNaNA.dhall
@@ -0,0 +1,6 @@
+{-
+    Equivalence must compare the result of the binary encoding, so in
+    particular comparing Doubles should not use standard float equality (where
+    NaN != NaN).
+-}
+assert : NaN === NaN
diff --git a/dhall-lang/tests/type-inference/success/unit/AssertNaNB.dhall b/dhall-lang/tests/type-inference/success/unit/AssertNaNB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/AssertNaNB.dhall
@@ -0,0 +1,1 @@
+NaN ≡ NaN
diff --git a/dhall-lang/tests/type-inference/success/unit/AssertSimpleA.dhall b/dhall-lang/tests/type-inference/success/unit/AssertSimpleA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/AssertSimpleA.dhall
@@ -0,0 +1,1 @@
+assert : (1 + 1) === 2
diff --git a/dhall-lang/tests/type-inference/success/unit/AssertSimpleB.dhall b/dhall-lang/tests/type-inference/success/unit/AssertSimpleB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/AssertSimpleB.dhall
@@ -0,0 +1,1 @@
+2 ≡ 2
diff --git a/dhall-lang/tests/type-inference/success/unit/AssertTrivialA.dhall b/dhall-lang/tests/type-inference/success/unit/AssertTrivialA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/AssertTrivialA.dhall
@@ -0,0 +1,1 @@
+assert : 1 === 1
diff --git a/dhall-lang/tests/type-inference/success/unit/AssertTrivialB.dhall b/dhall-lang/tests/type-inference/success/unit/AssertTrivialB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/AssertTrivialB.dhall
@@ -0,0 +1,1 @@
+1 ≡ 1
diff --git a/dhall-lang/tests/type-inference/success/unit/EquivalenceA.dhall b/dhall-lang/tests/type-inference/success/unit/EquivalenceA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/EquivalenceA.dhall
@@ -0,0 +1,1 @@
+1 === 2
diff --git a/dhall-lang/tests/type-inference/success/unit/EquivalenceB.dhall b/dhall-lang/tests/type-inference/success/unit/EquivalenceB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/EquivalenceB.dhall
@@ -0,0 +1,1 @@
+Type
diff --git a/dhall-lang/tests/type-inference/success/unit/FunctionDependentType1A.dhall b/dhall-lang/tests/type-inference/success/unit/FunctionDependentType1A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/FunctionDependentType1A.dhall
@@ -0,0 +1,1 @@
+λ(x : Bool) → Bool
diff --git a/dhall-lang/tests/type-inference/success/unit/FunctionDependentType1B.dhall b/dhall-lang/tests/type-inference/success/unit/FunctionDependentType1B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/FunctionDependentType1B.dhall
@@ -0,0 +1,1 @@
+∀(x : Bool) → Type
diff --git a/dhall-lang/tests/type-inference/success/unit/FunctionDependentType2A.dhall b/dhall-lang/tests/type-inference/success/unit/FunctionDependentType2A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/FunctionDependentType2A.dhall
@@ -0,0 +1,1 @@
+λ(x : Bool) → Type
diff --git a/dhall-lang/tests/type-inference/success/unit/FunctionDependentType2B.dhall b/dhall-lang/tests/type-inference/success/unit/FunctionDependentType2B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/FunctionDependentType2B.dhall
@@ -0,0 +1,1 @@
+∀(x : Bool) → Kind
diff --git a/dhall-lang/tests/type-inference/success/unit/FunctionTypeTypeKindA.dhall b/dhall-lang/tests/type-inference/success/unit/FunctionTypeTypeKindA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/FunctionTypeTypeKindA.dhall
@@ -0,0 +1,1 @@
+Type → Kind
diff --git a/dhall-lang/tests/type-inference/success/unit/FunctionTypeTypeKindB.dhall b/dhall-lang/tests/type-inference/success/unit/FunctionTypeTypeKindB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/FunctionTypeTypeKindB.dhall
@@ -0,0 +1,1 @@
+Sort
diff --git a/dhall-lang/tests/type-inference/success/unit/MergeEmptyAlternativeA.dhall b/dhall-lang/tests/type-inference/success/unit/MergeEmptyAlternativeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/MergeEmptyAlternativeA.dhall
@@ -0,0 +1,1 @@
+merge { x = 1 } < x >.x
diff --git a/dhall-lang/tests/type-inference/success/unit/MergeEmptyAlternativeB.dhall b/dhall-lang/tests/type-inference/success/unit/MergeEmptyAlternativeB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/MergeEmptyAlternativeB.dhall
@@ -0,0 +1,1 @@
+Natural
diff --git a/dhall-lang/tests/type-inference/success/unit/MergeTrickyShadowingA.dhall b/dhall-lang/tests/type-inference/success/unit/MergeTrickyShadowingA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/MergeTrickyShadowingA.dhall
@@ -0,0 +1,1 @@
+let _ = Bool in merge {_ = \(x: _) -> x} (<_: Bool>._ True)
diff --git a/dhall-lang/tests/type-inference/success/unit/MergeTrickyShadowingB.dhall b/dhall-lang/tests/type-inference/success/unit/MergeTrickyShadowingB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/MergeTrickyShadowingB.dhall
@@ -0,0 +1,1 @@
+Bool
diff --git a/dhall-lang/tests/type-inference/success/unit/NaturalSubtractA.dhall b/dhall-lang/tests/type-inference/success/unit/NaturalSubtractA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/NaturalSubtractA.dhall
@@ -0,0 +1,1 @@
+Natural/subtract
diff --git a/dhall-lang/tests/type-inference/success/unit/NaturalSubtractB.dhall b/dhall-lang/tests/type-inference/success/unit/NaturalSubtractB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/NaturalSubtractB.dhall
@@ -0,0 +1,1 @@
+Natural → Natural → Natural
diff --git a/dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeBoolTypeA.dhall b/dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeBoolTypeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeBoolTypeA.dhall
@@ -0,0 +1,1 @@
+{ x : Bool } ⩓ { y : Type }
diff --git a/dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeBoolTypeB.dhall b/dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeBoolTypeB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeBoolTypeB.dhall
@@ -0,0 +1,1 @@
+Kind
diff --git a/dhall-lang/tests/type-inference/success/unit/ToMapAnnotatedA.dhall b/dhall-lang/tests/type-inference/success/unit/ToMapAnnotatedA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/ToMapAnnotatedA.dhall
@@ -0,0 +1,1 @@
+toMap { foo = 1, bar = 4, baz = 9 } : List { mapKey : Text, mapValue : Natural }
diff --git a/dhall-lang/tests/type-inference/success/unit/ToMapAnnotatedB.dhall b/dhall-lang/tests/type-inference/success/unit/ToMapAnnotatedB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/type-inference/success/unit/ToMapAnnotatedB.dhall
@@ -0,0 +1,1 @@
+List { mapKey : Text, mapValue : Natural }
diff --git a/dhall-lang/tests/type-inference/success/unit/UnionLiteralOneA.dhall b/dhall-lang/tests/type-inference/success/unit/UnionLiteralOneA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/type-inference/success/unit/UnionLiteralOneA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x = True >
diff --git a/dhall-lang/tests/type-inference/success/unit/UnionLiteralOneB.dhall b/dhall-lang/tests/type-inference/success/unit/UnionLiteralOneB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/type-inference/success/unit/UnionLiteralOneB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x : Bool >
diff --git a/dhall-lang/tests/typecheck/failure/combineMixedRecords.dhall b/dhall-lang/tests/typecheck/failure/combineMixedRecords.dhall
deleted file mode 100644
--- a/dhall-lang/tests/typecheck/failure/combineMixedRecords.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-{ foo = 1 } ∧ { bar = Text }
diff --git a/dhall-lang/tests/typecheck/failure/duplicateFields.dhall b/dhall-lang/tests/typecheck/failure/duplicateFields.dhall
deleted file mode 100644
--- a/dhall-lang/tests/typecheck/failure/duplicateFields.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-{ a = 1, a = 2 }
diff --git a/dhall-lang/tests/typecheck/failure/preferMixedRecords.dhall b/dhall-lang/tests/typecheck/failure/preferMixedRecords.dhall
deleted file mode 100644
--- a/dhall-lang/tests/typecheck/failure/preferMixedRecords.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-{ foo = 1 } ⫽ { bar = Text }
diff --git a/dhall-lang/tests/typecheck/failure/recordOfKind.dhall b/dhall-lang/tests/typecheck/failure/recordOfKind.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/failure/recordOfKind.dhall
@@ -0,0 +1,1 @@
+{ a = Kind }
diff --git a/dhall-lang/tests/typecheck/success/RecordTypeMixedKindsA.dhall b/dhall-lang/tests/typecheck/success/RecordTypeMixedKindsA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/RecordTypeMixedKindsA.dhall
@@ -0,0 +1,1 @@
+{ x : Bool, y : Type }
diff --git a/dhall-lang/tests/typecheck/success/RecordTypeMixedKindsB.dhall b/dhall-lang/tests/typecheck/success/RecordTypeMixedKindsB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/RecordTypeMixedKindsB.dhall
@@ -0,0 +1,1 @@
+Kind
diff --git a/dhall-lang/tests/typecheck/success/preferMixedRecordsA.dhall b/dhall-lang/tests/typecheck/success/preferMixedRecordsA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/preferMixedRecordsA.dhall
@@ -0,0 +1,1 @@
+{ foo = 1 } ⫽ { bar = Text }
diff --git a/dhall-lang/tests/typecheck/success/preferMixedRecordsB.dhall b/dhall-lang/tests/typecheck/success/preferMixedRecordsB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/preferMixedRecordsB.dhall
@@ -0,0 +1,1 @@
+{ foo : Natural, bar : Type }
diff --git a/dhall-lang/tests/typecheck/success/preferMixedRecordsSameFieldA.dhall b/dhall-lang/tests/typecheck/success/preferMixedRecordsSameFieldA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/preferMixedRecordsSameFieldA.dhall
@@ -0,0 +1,1 @@
+{ a = 0 } ⫽ { a = Bool }
diff --git a/dhall-lang/tests/typecheck/success/preferMixedRecordsSameFieldB.dhall b/dhall-lang/tests/typecheck/success/preferMixedRecordsSameFieldB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/preferMixedRecordsSameFieldB.dhall
@@ -0,0 +1,1 @@
+{ a : Type }
diff --git a/dhall-lang/tests/typecheck/success/preludeA.dhall b/dhall-lang/tests/typecheck/success/preludeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/preludeA.dhall
@@ -0,0 +1,1 @@
+../../../Prelude/package.dhall
diff --git a/dhall-lang/tests/typecheck/success/preludeB.dhall b/dhall-lang/tests/typecheck/success/preludeB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/preludeB.dhall
@@ -0,0 +1,506 @@
+{ Bool :
+    { and :
+        ∀(xs : List Bool) → Bool
+    , build :
+        ∀(f : ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool) → Bool
+    , even :
+        ∀(xs : List Bool) → Bool
+    , fold :
+        ∀(b : Bool) → ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool
+    , not :
+        ∀(b : Bool) → Bool
+    , odd :
+        ∀(xs : List Bool) → Bool
+    , or :
+        ∀(xs : List Bool) → Bool
+    , show :
+        ∀(b : Bool) → Text
+    }
+, Double :
+    { show : Double → Text }
+, Function :
+    { compose :
+          ∀(A : Type)
+        → ∀(B : Type)
+        → ∀(C : Type)
+        → ∀(f : A → B)
+        → ∀(g : B → C)
+        → ∀(x : A)
+        → C
+    }
+, Integer :
+    { show : Integer → Text, toDouble : Integer → Double }
+, JSON :
+    { array :
+          ∀ ( x
+            : List
+                (   ∀(JSON : Type)
+                  → ∀ ( json
+                      : { array :
+                            List JSON → JSON
+                        , bool :
+                            Bool → JSON
+                        , null :
+                            JSON
+                        , number :
+                            Double → JSON
+                        , object :
+                            List { mapKey : Text, mapValue : JSON } → JSON
+                        , string :
+                            Text → JSON
+                        }
+                      )
+                  → JSON
+                )
+            )
+        → ∀(JSON : Type)
+        → ∀ ( json
+            : { array :
+                  List JSON → JSON
+              , bool :
+                  Bool → JSON
+              , null :
+                  JSON
+              , number :
+                  Double → JSON
+              , object :
+                  List { mapKey : Text, mapValue : JSON } → JSON
+              , string :
+                  Text → JSON
+              }
+            )
+        → JSON
+    , bool :
+          ∀(x : Bool)
+        → ∀(JSON : Type)
+        → ∀ ( json
+            : { array :
+                  List JSON → JSON
+              , bool :
+                  Bool → JSON
+              , null :
+                  JSON
+              , number :
+                  Double → JSON
+              , object :
+                  List { mapKey : Text, mapValue : JSON } → JSON
+              , string :
+                  Text → JSON
+              }
+            )
+        → JSON
+    , keyText :
+        ∀(key : Text) → ∀(value : Text) → { mapKey : Text, mapValue : Text }
+    , keyValue :
+          ∀(v : Type)
+        → ∀(key : Text)
+        → ∀(value : v)
+        → { mapKey : Text, mapValue : v }
+    , null :
+          ∀(JSON : Type)
+        → ∀ ( json
+            : { array :
+                  List JSON → JSON
+              , bool :
+                  Bool → JSON
+              , null :
+                  JSON
+              , number :
+                  Double → JSON
+              , object :
+                  List { mapKey : Text, mapValue : JSON } → JSON
+              , string :
+                  Text → JSON
+              }
+            )
+        → JSON
+    , number :
+          ∀(x : Double)
+        → ∀(JSON : Type)
+        → ∀ ( json
+            : { array :
+                  List JSON → JSON
+              , bool :
+                  Bool → JSON
+              , null :
+                  JSON
+              , number :
+                  Double → JSON
+              , object :
+                  List { mapKey : Text, mapValue : JSON } → JSON
+              , string :
+                  Text → JSON
+              }
+            )
+        → JSON
+    , object :
+          ∀ ( x
+            : List
+                { mapKey :
+                    Text
+                , mapValue :
+                      ∀(JSON : Type)
+                    → ∀ ( json
+                        : { array :
+                              List JSON → JSON
+                          , bool :
+                              Bool → JSON
+                          , null :
+                              JSON
+                          , number :
+                              Double → JSON
+                          , object :
+                              List { mapKey : Text, mapValue : JSON } → JSON
+                          , string :
+                              Text → JSON
+                          }
+                        )
+                    → JSON
+                }
+            )
+        → ∀(JSON : Type)
+        → ∀ ( json
+            : { array :
+                  List JSON → JSON
+              , bool :
+                  Bool → JSON
+              , null :
+                  JSON
+              , number :
+                  Double → JSON
+              , object :
+                  List { mapKey : Text, mapValue : JSON } → JSON
+              , string :
+                  Text → JSON
+              }
+            )
+        → JSON
+    , render :
+          ∀ ( j
+            :   ∀(JSON : Type)
+              → ∀ ( json
+                  : { array :
+                        List JSON → JSON
+                    , bool :
+                        Bool → JSON
+                    , null :
+                        JSON
+                    , number :
+                        Double → JSON
+                    , object :
+                        List { mapKey : Text, mapValue : JSON } → JSON
+                    , string :
+                        Text → JSON
+                    }
+                  )
+              → JSON
+            )
+        → Text
+    , string :
+          ∀(x : Text)
+        → ∀(JSON : Type)
+        → ∀ ( json
+            : { array :
+                  List JSON → JSON
+              , bool :
+                  Bool → JSON
+              , null :
+                  JSON
+              , number :
+                  Double → JSON
+              , object :
+                  List { mapKey : Text, mapValue : JSON } → JSON
+              , string :
+                  Text → JSON
+              }
+            )
+        → JSON
+    }
+, List :
+    { all :
+        ∀(a : Type) → ∀(f : a → Bool) → ∀(xs : List a) → Bool
+    , any :
+        ∀(a : Type) → ∀(f : a → Bool) → ∀(xs : List a) → Bool
+    , build :
+          ∀(a : Type)
+        → (∀(list : Type) → ∀(cons : a → list → list) → ∀(nil : list) → list)
+        → List a
+    , concat :
+        ∀(a : Type) → ∀(xss : List (List a)) → List a
+    , concatMap :
+        ∀(a : Type) → ∀(b : Type) → ∀(f : a → List b) → ∀(xs : List a) → List b
+    , filter :
+        ∀(a : Type) → ∀(f : a → Bool) → ∀(xs : List a) → List a
+    , fold :
+          ∀(a : Type)
+        → List a
+        → ∀(list : Type)
+        → ∀(cons : a → list → list)
+        → ∀(nil : list)
+        → list
+    , generate :
+        ∀(n : Natural) → ∀(a : Type) → ∀(f : Natural → a) → List a
+    , head :
+        ∀(a : Type) → List a → Optional a
+    , indexed :
+        ∀(a : Type) → List a → List { index : Natural, value : a }
+    , iterate :
+        ∀(n : Natural) → ∀(a : Type) → ∀(f : a → a) → ∀(x : a) → List a
+    , last :
+        ∀(a : Type) → List a → Optional a
+    , length :
+        ∀(a : Type) → List a → Natural
+    , map :
+        ∀(a : Type) → ∀(b : Type) → ∀(f : a → b) → ∀(xs : List a) → List b
+    , null :
+        ∀(a : Type) → ∀(xs : List a) → Bool
+    , replicate :
+        ∀(n : Natural) → ∀(a : Type) → ∀(x : a) → List a
+    , reverse :
+        ∀(a : Type) → List a → List a
+    , shifted :
+          ∀(a : Type)
+        → ∀(kvss : List (List { index : Natural, value : a }))
+        → List { index : Natural, value : a }
+    , unzip :
+          ∀(a : Type)
+        → ∀(b : Type)
+        → ∀(xs : List { _1 : a, _2 : b })
+        → { _1 : List a, _2 : List b }
+    }
+, Map :
+    { keys :
+          ∀(k : Type)
+        → ∀(v : Type)
+        → ∀(xs : List { mapKey : k, mapValue : v })
+        → List k
+    , map :
+          ∀(k : Type)
+        → ∀(a : Type)
+        → ∀(b : Type)
+        → ∀(f : a → b)
+        → ∀(m : List { mapKey : k, mapValue : a })
+        → List { mapKey : k, mapValue : b }
+    , values :
+          ∀(k : Type)
+        → ∀(v : Type)
+        → ∀(xs : List { mapKey : k, mapValue : v })
+        → List v
+    }
+, Natural :
+    { build :
+          (   ∀(natural : Type)
+            → ∀(succ : natural → natural)
+            → ∀(zero : natural)
+            → natural
+          )
+        → Natural
+    , enumerate :
+        ∀(n : Natural) → List Natural
+    , even :
+        Natural → Bool
+    , fold :
+          Natural
+        → ∀(natural : Type)
+        → ∀(succ : natural → natural)
+        → ∀(zero : natural)
+        → natural
+    , isZero :
+        Natural → Bool
+    , odd :
+        Natural → Bool
+    , product :
+        ∀(xs : List Natural) → Natural
+    , show :
+        Natural → Text
+    , sum :
+        ∀(xs : List Natural) → Natural
+    , toDouble :
+        ∀(n : Natural) → Double
+    , toInteger :
+        Natural → Integer
+    , lessThan :
+        Natural → Natural → Bool
+    , lessThanEqual :
+        Natural → Natural → Bool
+    , equal :
+        Natural → Natural → Bool
+    , greaterThan :
+        Natural → Natural → Bool
+    , greaterThanEqual :
+        Natural → Natural → Bool
+    }
+, Optional :
+    { all :
+        ∀(a : Type) → ∀(f : a → Bool) → ∀(xs : Optional a) → Bool
+    , any :
+        ∀(a : Type) → ∀(f : a → Bool) → ∀(xs : Optional a) → Bool
+    , build :
+          ∀(a : Type)
+        → (   ∀(optional : Type)
+            → ∀(just : a → optional)
+            → ∀(nothing : optional)
+            → optional
+          )
+        → Optional a
+    , concat :
+        ∀(a : Type) → ∀(x : Optional (Optional a)) → Optional a
+    , filter :
+        ∀(a : Type) → ∀(f : a → Bool) → ∀(xs : Optional a) → Optional a
+    , fold :
+          ∀(a : Type)
+        → Optional a
+        → ∀(optional : Type)
+        → ∀(just : a → optional)
+        → ∀(nothing : optional)
+        → optional
+    , head :
+        ∀(a : Type) → ∀(xs : List (Optional a)) → Optional a
+    , last :
+        ∀(a : Type) → ∀(xs : List (Optional a)) → Optional a
+    , length :
+        ∀(a : Type) → ∀(xs : Optional a) → Natural
+    , map :
+          ∀(a : Type)
+        → ∀(b : Type)
+        → ∀(f : a → b)
+        → ∀(o : Optional a)
+        → Optional b
+    , null :
+        ∀(a : Type) → ∀(xs : Optional a) → Bool
+    , toList :
+        ∀(a : Type) → ∀(o : Optional a) → List a
+    , unzip :
+          ∀(a : Type)
+        → ∀(b : Type)
+        → ∀(xs : Optional { _1 : a, _2 : b })
+        → { _1 : Optional a, _2 : Optional b }
+    }
+, Text :
+    { concat :
+        ∀(xs : List Text) → Text
+    , concatMap :
+        ∀(a : Type) → ∀(f : a → Text) → ∀(xs : List a) → Text
+    , concatMapSep :
+          ∀(separator : Text)
+        → ∀(a : Type)
+        → ∀(f : a → Text)
+        → ∀(elements : List a)
+        → Text
+    , concatSep :
+        ∀(separator : Text) → ∀(elements : List Text) → Text
+    , show :
+        Text → Text
+    }
+, XML :
+    { attribute :
+        ∀(key : Text) → ∀(value : Text) → { mapKey : Text, mapValue : Text }
+    , element :
+          ∀ ( elem
+            : { attributes :
+                  List { mapKey : Text, mapValue : Text }
+              , content :
+                  List
+                    (   ∀(XML : Type)
+                      → ∀ ( xml
+                          : { element :
+                                  { attributes :
+                                      List { mapKey : Text, mapValue : Text }
+                                  , content :
+                                      List XML
+                                  , name :
+                                      Text
+                                  }
+                                → XML
+                            , text :
+                                Text → XML
+                            }
+                          )
+                      → XML
+                    )
+              , name :
+                  Text
+              }
+            )
+        → ∀(XML : Type)
+        → ∀ ( xml
+            : { element :
+                    { attributes :
+                        List { mapKey : Text, mapValue : Text }
+                    , content :
+                        List XML
+                    , name :
+                        Text
+                    }
+                  → XML
+              , text :
+                  Text → XML
+              }
+            )
+        → XML
+    , emptyAttributes :
+        List { mapKey : Text, mapValue : Text }
+    , leaf :
+          ∀ ( elem
+            : { attributes :
+                  List { mapKey : Text, mapValue : Text }
+              , name :
+                  Text
+              }
+            )
+        → ∀(XML : Type)
+        → ∀ ( xml
+            : { element :
+                    { attributes :
+                        List { mapKey : Text, mapValue : Text }
+                    , content :
+                        List XML
+                    , name :
+                        Text
+                    }
+                  → XML
+              , text :
+                  Text → XML
+              }
+            )
+        → XML
+    , render :
+          ∀ ( x
+            :   ∀(XML : Type)
+              → ∀ ( xml
+                  : { element :
+                          { attributes :
+                              List { mapKey : Text, mapValue : Text }
+                          , content :
+                              List XML
+                          , name :
+                              Text
+                          }
+                        → XML
+                    , text :
+                        Text → XML
+                    }
+                  )
+              → XML
+            )
+        → Text
+    , text :
+          ∀(d : Text)
+        → ∀(XML : Type)
+        → ∀ ( xml
+            : { element :
+                    { attributes :
+                        List { mapKey : Text, mapValue : Text }
+                    , content :
+                        List XML
+                    , name :
+                        Text
+                    }
+                  → XML
+              , text :
+                  Text → XML
+              }
+            )
+        → XML
+    }
+}
diff --git a/dhall-lang/tests/typecheck/success/simple/RecordMixedKinds2A.dhall b/dhall-lang/tests/typecheck/success/simple/RecordMixedKinds2A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/simple/RecordMixedKinds2A.dhall
@@ -0,0 +1,1 @@
+{ x = Type, y = {} }
diff --git a/dhall-lang/tests/typecheck/success/simple/RecordMixedKinds2B.dhall b/dhall-lang/tests/typecheck/success/simple/RecordMixedKinds2B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/simple/RecordMixedKinds2B.dhall
@@ -0,0 +1,1 @@
+{ x : Kind, y : Type }
diff --git a/dhall-lang/tests/typecheck/success/simple/RecordMixedKindsA.dhall b/dhall-lang/tests/typecheck/success/simple/RecordMixedKindsA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/simple/RecordMixedKindsA.dhall
@@ -0,0 +1,1 @@
+{ x = {=}, y = Bool }
diff --git a/dhall-lang/tests/typecheck/success/simple/RecordMixedKindsB.dhall b/dhall-lang/tests/typecheck/success/simple/RecordMixedKindsB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/simple/RecordMixedKindsB.dhall
@@ -0,0 +1,1 @@
+{ x : {}, y : Type }
diff --git a/dhall-lang/tests/typecheck/success/simple/RecursiveRecordMergeMixedKindsA.dhall b/dhall-lang/tests/typecheck/success/simple/RecursiveRecordMergeMixedKindsA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/simple/RecursiveRecordMergeMixedKindsA.dhall
@@ -0,0 +1,1 @@
+{ x = True } ∧ { y = Bool }
diff --git a/dhall-lang/tests/typecheck/success/simple/RecursiveRecordMergeMixedKindsB.dhall b/dhall-lang/tests/typecheck/success/simple/RecursiveRecordMergeMixedKindsB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/simple/RecursiveRecordMergeMixedKindsB.dhall
@@ -0,0 +1,1 @@
+{ x : Bool, y : Type }
diff --git a/dhall-lang/tests/typecheck/success/simple/RightBiasedRecordMergeMixedKindsA.dhall b/dhall-lang/tests/typecheck/success/simple/RightBiasedRecordMergeMixedKindsA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/simple/RightBiasedRecordMergeMixedKindsA.dhall
@@ -0,0 +1,1 @@
+{ x = {=} } ⫽ { x = Bool }
diff --git a/dhall-lang/tests/typecheck/success/simple/RightBiasedRecordMergeMixedKindsB.dhall b/dhall-lang/tests/typecheck/success/simple/RightBiasedRecordMergeMixedKindsB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/simple/RightBiasedRecordMergeMixedKindsB.dhall
@@ -0,0 +1,1 @@
+{ x : Type }
diff --git a/dhall-lang/tests/typecheck/success/simple/combineMixedRecordsA.dhall b/dhall-lang/tests/typecheck/success/simple/combineMixedRecordsA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/simple/combineMixedRecordsA.dhall
@@ -0,0 +1,1 @@
+{ foo = 1 } ∧ { bar = Text }
diff --git a/dhall-lang/tests/typecheck/success/simple/combineMixedRecordsB.dhall b/dhall-lang/tests/typecheck/success/simple/combineMixedRecordsB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/simple/combineMixedRecordsB.dhall
@@ -0,0 +1,1 @@
+{ foo : Natural, bar : Type }
diff --git a/dhall.cabal b/dhall.cabal
--- a/dhall.cabal
+++ b/dhall.cabal
@@ -1,5 +1,5 @@
 Name: dhall
-Version: 1.25.0
+Version: 1.26.0
 Cabal-Version: >=1.10
 Build-Type: Simple
 Tested-With: GHC == 7.10.3, GHC == 8.4.3, GHC == 8.6.1
@@ -43,11 +43,19 @@
     dhall-lang/Prelude/Integer/package.dhall
     dhall-lang/Prelude/Integer/show
     dhall-lang/Prelude/Integer/toDouble
+    dhall-lang/Prelude/JSON/array
+    dhall-lang/Prelude/JSON/bool
     dhall-lang/Prelude/JSON/keyText
     dhall-lang/Prelude/JSON/keyValue
     dhall-lang/Prelude/JSON/Nesting
+    dhall-lang/Prelude/JSON/null
+    dhall-lang/Prelude/JSON/number
+    dhall-lang/Prelude/JSON/object
     dhall-lang/Prelude/JSON/package.dhall
+    dhall-lang/Prelude/JSON/render
+    dhall-lang/Prelude/JSON/string
     dhall-lang/Prelude/JSON/Tagged
+    dhall-lang/Prelude/JSON/Type
     dhall-lang/Prelude/List/all
     dhall-lang/Prelude/List/any
     dhall-lang/Prelude/List/build
@@ -68,12 +76,23 @@
     dhall-lang/Prelude/List/reverse
     dhall-lang/Prelude/List/shifted
     dhall-lang/Prelude/List/unzip
+    dhall-lang/Prelude/Map/Entry
+    dhall-lang/Prelude/Map/keys
+    dhall-lang/Prelude/Map/map
+    dhall-lang/Prelude/Map/package.dhall
+    dhall-lang/Prelude/Map/Type
+    dhall-lang/Prelude/Map/values
     dhall-lang/Prelude/Monoid
     dhall-lang/Prelude/Natural/build
     dhall-lang/Prelude/Natural/enumerate
+    dhall-lang/Prelude/Natural/equal
     dhall-lang/Prelude/Natural/even
     dhall-lang/Prelude/Natural/fold
+    dhall-lang/Prelude/Natural/greaterThan
+    dhall-lang/Prelude/Natural/greaterThanEqual
     dhall-lang/Prelude/Natural/isZero
+    dhall-lang/Prelude/Natural/lessThan
+    dhall-lang/Prelude/Natural/lessThanEqual
     dhall-lang/Prelude/Natural/odd
     dhall-lang/Prelude/Natural/package.dhall
     dhall-lang/Prelude/Natural/product
@@ -102,6 +121,14 @@
     dhall-lang/Prelude/Text/concatSep
     dhall-lang/Prelude/Text/package.dhall
     dhall-lang/Prelude/Text/show
+    dhall-lang/Prelude/XML/attribute
+    dhall-lang/Prelude/XML/element
+    dhall-lang/Prelude/XML/emptyAttributes
+    dhall-lang/Prelude/XML/leaf
+    dhall-lang/Prelude/XML/package.dhall
+    dhall-lang/Prelude/XML/render
+    dhall-lang/Prelude/XML/text
+    dhall-lang/Prelude/XML/Type
     dhall-lang/tests/binary-decode/failure/unit/*.dhallb
     dhall-lang/tests/binary-decode/success/unit/*.dhall
     dhall-lang/tests/binary-decode/success/unit/*.dhallb
@@ -116,124 +143,6 @@
     dhall-lang/tests/normalization/success/haskell-tutorial/combineTypes/*.dhall
     dhall-lang/tests/normalization/success/haskell-tutorial/prefer/*.dhall
     dhall-lang/tests/normalization/success/haskell-tutorial/projection/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/and/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/and/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/build/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/build/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/even/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/even/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/fold/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/fold/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/not/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/not/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/odd/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/odd/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/or/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/or/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/show/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Bool/show/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Double/show/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Double/show/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Integer/show/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Integer/show/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Integer/toDouble/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Integer/toDouble/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/all/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/all/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/any/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/any/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/build/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/build/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/concat/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/concat/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/concatMap/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/concatMap/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/filter/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/filter/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/fold/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/fold/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/generate/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/generate/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/head/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/head/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/indexed/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/indexed/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/iterate/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/iterate/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/last/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/last/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/length/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/length/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/map/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/map/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/null/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/null/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/replicate/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/replicate/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/reverse/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/reverse/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/shifted/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/shifted/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/unzip/*.dhall
-    dhall-lang/tests/normalization/success/prelude/List/unzip/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/build/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/build/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/enumerate/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/enumerate/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/even/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/even/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/fold/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/fold/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/isZero/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/isZero/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/odd/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/odd/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/product/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/product/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/show/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/show/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/sum/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/sum/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/toDouble/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/toDouble/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/toInteger/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Natural/toInteger/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/all/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/all/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/any/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/any/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/build/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/build/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/concat/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/concat/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/filter/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/filter/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/fold/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/fold/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/head/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/head/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/last/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/last/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/length/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/length/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/map/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/map/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/null/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/null/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/toList/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/toList/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/unzip/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Optional/unzip/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Text/concat/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Text/concat/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Text/concatMap/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Text/concatMap/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Text/concatSep/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Text/concatSep/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Text/show/*.dhall
-    dhall-lang/tests/normalization/success/prelude/Text/show/*.dhall
     dhall-lang/tests/normalization/success/simple/*.dhall
     dhall-lang/tests/normalization/success/simplifications/*.dhall
     dhall-lang/tests/normalization/success/unit/*.dhall
@@ -509,6 +418,7 @@
     tests/lint/success/*.dhall
     tests/diff/*.dhall
     tests/diff/*.txt
+    tests/recursive/*.dhall
     tests/regression/*.dhall
     tests/tutorial/*.dhall
 
@@ -532,7 +442,7 @@
         base                        >= 4.8.2.0  && < 5   ,
         aeson                       >= 1.0.0.0  && < 1.5 ,
         aeson-pretty                               < 0.9 ,
-        ansi-terminal               >= 0.6.3.1  && < 0.10,
+        ansi-terminal               >= 0.6.3.1  && < 0.11,
         bytestring                                 < 0.11,
         case-insensitive                           < 1.3 ,
         cborg                       >= 0.2.0.0  && < 0.3 ,
@@ -540,23 +450,25 @@
         containers                  >= 0.5.0.0  && < 0.7 ,
         contravariant                              < 1.6 ,
         cryptonite                  >= 0.23     && < 1.0 ,
+        data-fix                                   < 0.3 ,
         deepseq                                    < 1.5 ,
         Diff                        >= 0.2      && < 0.4 ,
         directory                   >= 1.2.2.0  && < 1.4 ,
         dotgen                      >= 0.4.2    && < 0.5 ,
-        either,
+        either                      >= 5        && < 5.1,
         exceptions                  >= 0.8.3    && < 0.11,
         filepath                    >= 1.4      && < 1.5 ,
         haskeline                   >= 0.7.2.1  && < 0.8 ,
         lens-family-core            >= 1.0.0    && < 2.1 ,
         megaparsec                  >= 6.5.0    && < 7.1 ,
-        memory                      >= 0.14     && < 0.15,
+        memory                      >= 0.14     && < 0.16,
         mtl                         >= 2.2.1    && < 2.3 ,
+        network-uri                 >= 2.6      && < 2.7 ,
         optparse-applicative        >= 0.14.0.0 && < 0.16,
         parsers                     >= 0.12.4   && < 0.13,
         prettyprinter               >= 1.2.0.1  && < 1.3 ,
         prettyprinter-ansi-terminal >= 1.1.1    && < 1.2 ,
-        profunctors                 >= 3.1.2    && < 5.5 ,
+        profunctors                 >= 3.1.2    && < 5.6 ,
         repline                     >= 0.2.1.0  && < 0.3 ,
         serialise                   >= 0.2.0.0  && < 0.3 ,
         scientific                  >= 0.3.0.0  && < 0.4 ,
@@ -630,7 +542,8 @@
         Dhall.Pretty,
         Dhall.Repl,
         Dhall.Tutorial,
-        Dhall.TypeCheck
+        Dhall.TypeCheck,
+        Dhall.Util
     if !flag(cross)
         Exposed-Modules:
             Dhall.TH
@@ -639,8 +552,6 @@
         Dhall.Parser.Combinators,
         Dhall.Import.Types,
         Dhall.Eval,
-        Dhall.Util,
-        Dhall.X
         Paths_dhall
     if flag(with-http)
       Other-Modules:
@@ -681,21 +592,25 @@
         bytestring                               < 0.11,
         cborg                     >= 0.2.0.0  && < 0.3 ,
         containers                                     ,
+        data-fix                                       ,
         deepseq                   >= 1.2.0.1  && < 1.5 ,
         dhall                                          ,
         directory                                      ,
         filepath                                       ,
         foldl                                    < 1.5 ,
+        generic-random            >= 1.3.0.0  && < 1.4 ,
         lens-family-core          >= 1.0.0    && < 2.1 ,
         megaparsec                                     ,
         prettyprinter                                  ,
         QuickCheck                >= 2.10     && < 2.14,
         quickcheck-instances      >= 0.3.12   && < 0.4 ,
+        scientific                                     ,
         semigroups                                     ,
         serialise                                      ,
         spoon                                    < 0.4 ,
         tasty                     >= 0.11.2   && < 1.3 ,
-        tasty-hunit               >= 0.9.2    && < 0.11,
+        tasty-expected-failure                   < 0.12,
+        tasty-hunit               >= 0.10     && < 0.11,
         tasty-quickcheck          >= 0.9.2    && < 0.11,
         text                      >= 0.11.1.0 && < 1.3 ,
         transformers                                   ,
diff --git a/src/Dhall.hs b/src/Dhall.hs
--- a/src/Dhall.hs
+++ b/src/Dhall.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE ConstraintKinds            #-}
 {-# LANGUAGE DefaultSignatures          #-}
 {-# LANGUAGE DeriveFunctor              #-}
 {-# LANGUAGE DeriveGeneric              #-}
@@ -6,12 +7,15 @@
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE MultiWayIf                 #-}
 {-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE PolyKinds                  #-}
 {-# LANGUAGE RankNTypes                 #-}
 {-# LANGUAGE RecordWildCards            #-}
 {-# LANGUAGE ScopedTypeVariables        #-}
 {-# LANGUAGE StandaloneDeriving         #-}
+{-# LANGUAGE TypeFamilies               #-}
 {-# LANGUAGE TypeOperators              #-}
 {-# LANGUAGE TupleSections              #-}
+{-# LANGUAGE UndecidableInstances       #-}
 
 {-| Please read the "Dhall.Tutorial" module, which contains a tutorial explaining
     how to use the language, the compiler, and this library
@@ -30,7 +34,6 @@
     , sourceName
     , startingContext
     , normalizer
-    , standardVersion
     , defaultInputSettings
     , InputSettings
     , defaultEvaluateSettings
@@ -109,6 +112,7 @@
 import Control.Monad (guard)
 import Data.Coerce (coerce)
 import Data.Either.Validation (Validation(..), ealt, eitherToValidation, validationToEither)
+import Data.Fix (Fix(..))
 import Data.Functor.Contravariant (Contravariant(..), (>$<), Op(..))
 import Data.Functor.Contravariant.Divisible (Divisible(..), divided)
 import Data.List.NonEmpty (NonEmpty (..))
@@ -121,7 +125,6 @@
 import Data.Typeable (Typeable)
 import Data.Vector (Vector)
 import Data.Word (Word8, Word16, Word32, Word64)
-import Dhall.Binary (StandardVersion(..))
 import Dhall.Core (Expr(..), Chunks(..))
 import Dhall.Import (Imported(..))
 import Dhall.Parser (Src(..))
@@ -148,7 +151,6 @@
 import qualified Data.Text.IO
 import qualified Data.Text.Lazy
 import qualified Data.Vector
-import qualified Dhall.Binary
 import qualified Dhall.Context
 import qualified Dhall.Core
 import qualified Dhall.Import
@@ -297,7 +299,6 @@
 data EvaluateSettings = EvaluateSettings
   { _startingContext :: Dhall.Context.Context (Expr Src X)
   , _normalizer      :: Maybe (Dhall.Core.ReifiedNormalizer X)
-  , _standardVersion :: StandardVersion
   }
 
 -- | Default evaluation settings: no extra entries in the initial
@@ -308,7 +309,6 @@
 defaultEvaluateSettings = EvaluateSettings
   { _startingContext = Dhall.Context.empty
   , _normalizer      = Nothing
-  , _standardVersion = Dhall.Binary.defaultStandardVersion
   }
 
 -- | Access the starting context used for evaluation and type-checking.
@@ -335,17 +335,6 @@
       => LensLike' f EvaluateSettings (Maybe (Dhall.Core.ReifiedNormalizer X))
     l k s = fmap (\x -> s { _normalizer = x }) (k (_normalizer s))
 
--- | Access the standard version (used primarily when encoding or decoding
--- Dhall expressions to and from a binary representation)
---
--- @since 1.17
-standardVersion
-    :: (Functor f, HasEvaluateSettings s)
-    => LensLike' f s StandardVersion
-standardVersion = evaluateSettings . l
-  where
-  l k s = fmap (\x -> s { _standardVersion = x}) (k (_standardVersion s))
-
 -- | @since 1.16
 class HasEvaluateSettings s where
   evaluateSettings
@@ -408,8 +397,7 @@
     let EvaluateSettings {..} = _evaluateSettings
 
     let transform =
-               set Dhall.Import.standardVersion _standardVersion
-            .  set Dhall.Import.normalizer      _normalizer
+               set Dhall.Import.normalizer      _normalizer
             .  set Dhall.Import.startingContext _startingContext
 
     let status = transform (Dhall.Import.emptyStatus _rootDirectory)
@@ -503,8 +491,7 @@
     let EvaluateSettings {..} = _evaluateSettings
 
     let transform =
-               set Dhall.Import.standardVersion _standardVersion
-            .  set Dhall.Import.normalizer      _normalizer
+               set Dhall.Import.normalizer      _normalizer
             .  set Dhall.Import.startingContext _startingContext
 
     let status = transform (Dhall.Import.emptyStatus _rootDirectory)
@@ -918,6 +905,114 @@
 auto :: Interpret a => Type a
 auto = autoWith defaultInterpretOptions
 
+{-| This type is exactly the same as `Data.Fix.Fix` except with a different
+    `Interpret` instance.  This intermediate type simplies the implementation
+    of the inner loop for the `Interpret` instance for `Fix`
+-}
+newtype Result f = Result { _unResult :: f (Result f) }
+
+resultToFix :: Functor f => Result f -> Fix f
+resultToFix (Result x) = Fix (fmap resultToFix x)
+
+instance Interpret (f (Result f)) => Interpret (Result f) where
+    autoWith options = Type { expected = expected_, extract = extract_ }
+      where
+        expected_ = "result"
+
+        extract_ (App _ expression) = do
+            fmap Result (extract (autoWith options) expression)
+        extract_ expression = do
+            typeError expression expected_
+
+-- | You can use this instance to marshal recursive types from Dhall to Haskell.
+--
+-- Here is an example use of this instance:
+--
+-- > {-# LANGUAGE DeriveAnyClass     #-}
+-- > {-# LANGUAGE DeriveFoldable     #-}
+-- > {-# LANGUAGE DeriveFunctor      #-}
+-- > {-# LANGUAGE DeriveTraversable  #-}
+-- > {-# LANGUAGE DeriveGeneric      #-}
+-- > {-# LANGUAGE KindSignatures     #-}
+-- > {-# LANGUAGE QuasiQuotes        #-}
+-- > {-# LANGUAGE StandaloneDeriving #-}
+-- > {-# LANGUAGE TypeFamilies       #-}
+-- > {-# LANGUAGE TemplateHaskell    #-}
+-- > 
+-- > import Data.Fix (Fix(..))
+-- > import Data.Text (Text)
+-- > import Dhall (Interpret)
+-- > import GHC.Generics (Generic)
+-- > import Numeric.Natural (Natural)
+-- > 
+-- > import qualified Data.Fix                 as Fix
+-- > import qualified Data.Functor.Foldable    as Foldable
+-- > import qualified Data.Functor.Foldable.TH as TH
+-- > import qualified Dhall
+-- > import qualified NeatInterpolation
+-- > 
+-- > data Expr
+-- >     = Lit Natural
+-- >     | Add Expr Expr
+-- >     | Mul Expr Expr
+-- >     deriving (Show)
+-- > 
+-- > TH.makeBaseFunctor ''Expr
+-- > 
+-- > deriving instance Generic (ExprF a)
+-- > deriving instance Interpret a => Interpret (ExprF a)
+-- > 
+-- > example :: Text
+-- > example = [NeatInterpolation.text|
+-- >     \(Expr : Type)
+-- > ->  let ExprF =
+-- >           < LitF :
+-- >               { _1 : Natural }
+-- >           | AddF :
+-- >               { _1 : Expr, _2 : Expr }
+-- >           | MulF :
+-- >               { _1 : Expr, _2 : Expr }
+-- >           >
+-- >     
+-- >     in      \(Fix : ExprF -> Expr)
+-- >         ->  let Lit = \(x : Natural) -> Fix (ExprF.LitF { _1 = x })
+-- >             
+-- >             let Add =
+-- >                       \(x : Expr)
+-- >                   ->  \(y : Expr)
+-- >                   ->  Fix (ExprF.AddF { _1 = x, _2 = y })
+-- >             
+-- >             let Mul =
+-- >                       \(x : Expr)
+-- >                   ->  \(y : Expr)
+-- >                   ->  Fix (ExprF.MulF { _1 = x, _2 = y })
+-- >             
+-- >             in  Add (Mul (Lit 3) (Lit 7)) (Add (Lit 1) (Lit 2))
+-- > |]
+-- > 
+-- > convert :: Fix ExprF -> Expr
+-- > convert = Fix.cata Foldable.embed
+-- > 
+-- > main :: IO ()
+-- > main = do
+-- >     x <- Dhall.input Dhall.auto example :: IO (Fix ExprF)
+-- > 
+-- >     print (convert x :: Expr)
+instance (Functor f, Interpret (f (Result f))) => Interpret (Fix f) where
+    autoWith options = Type { expected = expected_, extract = extract_ }
+      where
+        expected_ =
+            Pi "result" (Const Dhall.Core.Type)
+                (Pi "Make" (Pi "_" (expected (autoWith options :: Type (f (Result f)))) "result")
+                    "result"
+                )
+
+        extract_ expression0 = go0 (Dhall.Core.alphaNormalize expression0)
+          where
+            go0 (Lam _ _ (Lam _ _  expression1)) =
+                fmap resultToFix (extract (autoWith options) expression1)
+            go0 _ = typeError expected_ expression0
+
 {-| `genericAuto` is the default implementation for `auto` if you derive
     `Interpret`.  The difference is that you can use `genericAuto` without
     having to explicitly provide an `Interpret` instance for a type as long as
@@ -1017,8 +1112,6 @@
     _                 -> Just e
 extractUnionConstructor
     :: Expr s a -> Maybe (Text, Expr s a, Dhall.Map.Map Text (Maybe (Expr s a)))
-extractUnionConstructor (UnionLit fld e rest) =
-  return (fld, e, rest)
 extractUnionConstructor (App (Field (Union kts) fld) e) =
   return (fld, e, Dhall.Map.delete fld kts)
 extractUnionConstructor (Field (Union kts) fld) =
@@ -1246,6 +1339,10 @@
 
         declared = Text
 
+instance {-# OVERLAPS #-} Inject String where
+    injectWith options =
+        contramap Data.Text.pack (injectWith options :: InputType Text)
+
 instance Inject Natural where
     injectWith _ = InputType {..}
       where
@@ -1302,6 +1399,10 @@
 
         declared = Double
 
+instance Inject Scientific where
+    injectWith options =
+        contramap Data.Scientific.toRealFloat (injectWith options :: InputType Double)
+
 instance Inject () where
     injectWith _ = InputType {..}
       where
@@ -1322,7 +1423,11 @@
 instance Inject a => Inject (Seq a) where
     injectWith options = InputType embedOut declaredOut
       where
-        embedOut xs = ListLit (Just declaredIn) (fmap embedIn xs)
+        embedOut xs = ListLit listType (fmap embedIn xs)
+          where
+            listType
+                | null xs   = Just (App List declaredIn)
+                | otherwise = Nothing
 
         declaredOut = App List declaredIn
 
@@ -1616,10 +1721,10 @@
     And assume that we have the following Dhall union that we would like to
     parse as a @Status@:
 
-> < Result = "Finish succesfully"
+> < Result : Text
 > | Queued : Natural
 > | Errored : Text
-> >
+> >.Result "Finish successfully"
 
     Our parser has type 'Type' @Status@, but we can't build that out of any
     smaller parsers, as 'Type's cannot be combined (they are only 'Functor's).
@@ -1760,8 +1865,8 @@
     recordType = Record $ declared <$> inputTypeRecord
     makeRecordLit x = RecordLit $ (($ x) . embed) <$> inputTypeRecord
 
-{-| The 'UnionInputType' monoid allows you to build
-    an 'InputType' injector for a Dhall record.
+{-| 'UnionInputType' allows you to build an 'InputType' injector for a Dhall
+    record.
 
     For example, let's take the following Haskell data type:
 
@@ -1774,10 +1879,10 @@
     And assume that we have the following Dhall union that we would like to
     parse as a @Status@:
 
-> < Result = "Finish succesfully"
+> < Result : Text
 > | Queued : Natural
 > | Errored : Text
-> >
+> >.Result "Finish successfully"
 
     Our injector has type 'InputType' @Status@, but we can't build that out of any
     smaller injectors, as 'InputType's cannot be combined.
diff --git a/src/Dhall/Binary.hs b/src/Dhall/Binary.hs
--- a/src/Dhall/Binary.hs
+++ b/src/Dhall/Binary.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE FlexibleContexts   #-}
 {-# LANGUAGE FlexibleInstances  #-}
 {-# LANGUAGE RecordWildCards    #-}
 {-# LANGUAGE OverloadedStrings  #-}
@@ -10,8 +11,6 @@
 module Dhall.Binary
     ( -- * Standard versions
       StandardVersion(..)
-    , defaultStandardVersion
-    , parseStandardVersion
     , renderStandardVersion
 
     -- * Encoding and decoding
@@ -39,18 +38,16 @@
     , ImportHashed(..)
     , ImportMode(..)
     , ImportType(..)
+    , MultiLet(..)
     , Scheme(..)
     , URL(..)
     , Var(..)
     )
 
-import Dhall.X (X(..))
 import Data.Foldable (toList)
-import Data.List.NonEmpty (NonEmpty(..))
 import Data.Monoid ((<>))
 import Data.Text (Text)
-import Options.Applicative (Parser)
-import Prelude hiding (exponent)
+import Data.Void (Void, absurd)
 import GHC.Float (double2Float, float2Double)
 
 import qualified Crypto.Hash
@@ -61,7 +58,6 @@
 import qualified Dhall.Core
 import qualified Dhall.Map
 import qualified Dhall.Set
-import qualified Options.Applicative
 
 -- | Supported version strings
 data StandardVersion
@@ -79,29 +75,6 @@
     -- ^ Version "1.0.0"
     deriving (Enum, Bounded)
 
-defaultStandardVersion :: StandardVersion
-defaultStandardVersion = NoVersion
-
-parseStandardVersion :: Parser StandardVersion
-parseStandardVersion =
-    Options.Applicative.option readVersion
-        (   Options.Applicative.long "standard-version"
-        <>  Options.Applicative.metavar "X.Y.Z"
-        <>  Options.Applicative.help "The standard version to use"
-        <>  Options.Applicative.value defaultStandardVersion
-        )
-  where
-    readVersion = do
-        string <- Options.Applicative.str
-        case string :: Text of
-            "none"  -> return NoVersion
-            "1.0.0" -> return V_1_0_0
-            "2.0.0" -> return V_2_0_0
-            "3.0.0" -> return V_3_0_0
-            "4.0.0" -> return V_4_0_0
-            "5.0.0" -> return V_5_0_0
-            _       -> fail "Unsupported version"
-
 renderStandardVersion :: StandardVersion -> Text
 renderStandardVersion NoVersion = "none"
 renderStandardVersion V_1_0_0   = "1.0.0"
@@ -130,7 +103,7 @@
 class ToTerm a where
     encode :: a -> Term
 
-instance ToTerm a => ToTerm (Expr X a) where
+instance ToTerm a => ToTerm (Expr Void a) where
     encode (Var (V "_" n)) =
         TInt n
     encode (Var (V x n)) =
@@ -149,6 +122,8 @@
         TString "Natural/toInteger"
     encode NaturalShow =
         TString "Natural/show"
+    encode NaturalSubtract =
+        TString "Natural/subtract"
     encode IntegerToDouble =
         TString "Integer/toDouble"
     encode IntegerShow =
@@ -283,6 +258,11 @@
       where
         l₁ = encode l₀
         r₁ = encode r₀
+    encode (Equivalent l₀ r₀) =
+        TList [ TInt 3, TInt 12, l₁, r₁ ]
+      where
+        l₁ = encode l₀
+        r₁ = encode r₀
     encode (ListLit _T₀ xs₀)
         | null xs₀  = TList [ TInt label, _T₁ ]
         | otherwise = TList ([ TInt 4, TNull ] ++ xs₁)
@@ -351,18 +331,6 @@
                     Just _T₀ -> encode _T₀
 
             return (x₁, _T₁)
-    encode (UnionLit x t₀ yTs₀) =
-        TList [ TInt 12, TString x, t₁, TMap yTs₁ ]
-      where
-        t₁ = encode t₀
-
-        yTs₁ = do
-            (y₀, mT₀) <- Dhall.Map.toList (Dhall.Map.sort yTs₀)
-            let y₁  = TString y₀
-            let _T₁ = case mT₀ of
-                    Just _T₀ -> encode _T₀
-                    Nothing  -> TNull
-            return (y₁, _T₁)
     encode (BoolLit b) =
         TBool b
     encode (BoolIf t₀ l₀ r₀) =
@@ -397,21 +365,27 @@
             [ x₁, y₁ ]
 
         z₁ = TString z₀
+    encode (Assert t₀) =
+        TList [ TInt 19, t₁ ]
+      where
+        t₁ = encode t₀
     encode (Embed x) =
         encode x
-    encode (Let as₀ b₀) =
+    encode (Let a b) =
         TList ([ TInt 25 ] ++ as₁ ++ [ b₁ ])
       where
+        MultiLet as₀ b₀ = Dhall.Core.multiLet a b
+
         as₁ = do
-            Binding x mA₀ a₀ <- toList as₀
+            Binding _ x₀ _ mA₀ _ a₀ <- toList as₀
 
             let mA₁ = case mA₀ of
-                    Nothing  -> TNull
-                    Just _A₀ -> encode _A₀
+                    Nothing       -> TNull
+                    Just (_, _A₀) -> encode _A₀
 
             let a₁ = encode a₀
 
-            [ TString x, mA₁, a₁ ]
+            [ TString x₀, mA₁, a₁ ]
 
         b₁ = encode b₀
     encode (Annot t₀ _T₀) =
@@ -428,7 +402,7 @@
       where
         t₁  = encode t₀
         _T₁ = encode _T₀
-    encode (Note (X absurd) _) = absurd
+    encode (Note a _) = absurd a
 
 instance ToTerm Import where
     encode import_ =
@@ -495,7 +469,7 @@
 
         ImportHashed {..} = importHashed
 
-instance ToTerm X where
+instance ToTerm Void where
     encode = absurd
 
 -- | Types that can be decoded from a CBOR `Term`
@@ -521,6 +495,8 @@
         return NaturalToInteger
     decode (TString "Natural/show") =
         return NaturalShow
+    decode (TString "Natural/subtract") =
+        return NaturalSubtract
     decode (TString "Integer/toDouble") =
         return IntegerToDouble
     decode (TString "Integer/show") =
@@ -616,6 +592,7 @@
                 9  -> return Prefer
                 10 -> return CombineTypes
                 11 -> return ImportAlt
+                12 -> return Equivalent
                 _  -> empty
         return (op l₀ r₀)
     decode (TList [ TInt 4, _T₁ ]) = do
@@ -698,21 +675,6 @@
         xTs₀ <- traverse process xTs₁
 
         return (Union (Dhall.Map.fromList xTs₀))
-    decode (TList [ TInt 12, TString x, t₁, TMap yTs₁ ]) = do
-        t₀ <- decode t₁
-
-        let process (TString y, _T₁) = do
-                _T₀ <- case _T₁ of
-                    TNull -> return Nothing
-                    _     -> fmap Just (decode _T₁)
-
-                return (y, _T₀)
-            process _ =
-                empty
-
-        yTs₀ <- traverse process yTs₁
-
-        return (UnionLit x t₀ (Dhall.Map.fromList yTs₀))
     decode (TBool b) = do
         return (BoolLit b)
     decode (TList [ TInt 14, t₁, l₁, r₁ ]) = do
@@ -751,26 +713,26 @@
         (xys, z) <- process xs
 
         return (TextLit (Chunks xys z))
+    decode (TList [ TInt 19, t₁ ]) = do
+        t₀ <- decode t₁
+
+        return (Assert t₀)
     decode e@(TList (TInt 24 : _)) = fmap Embed (decode e)
     decode (TList (TInt 25 : xs)) = do
         let process (TString x : _A₁ : a₁ : ls₁) = do
                 mA₀ <- case _A₁ of
                     TNull -> return Nothing
-                    _     -> fmap Just (decode _A₁)
+                    _     -> do
+                        _A₀ <- decode _A₁
+                        return (Just (Nothing, _A₀))
 
                 a₀  <- decode a₁
 
-                let binding = Binding x mA₀ a₀
-
-                case ls₁ of
-                    [ b₁ ] -> do
-                        b₀ <- decode b₁
-
-                        return (Let (binding :| []) b₀)
-                    _ -> do
-                        Let (l₀ :| ls₀) b₀ <- process ls₁
+                b₀ <- case ls₁ of
+                    [ b₁ ] -> decode b₁
+                    _      -> process ls₁
 
-                        return (Let (binding :| (l₀ : ls₀)) b₀)
+                return (Let (Binding Nothing x Nothing mA₀ Nothing a₀) b₀)
             process _ = do
                 empty
 
@@ -893,7 +855,7 @@
 
     decode _ = empty
 
-instance FromTerm X where
+instance FromTerm Void where
     decode _ = empty
 
 strip55799Tag :: Term -> Term
@@ -945,7 +907,7 @@
 -- This 'Dhall.Core.denote's the expression before encoding it. To encode an
 -- already denoted expression, it is more efficient to directly use 'encode'.
 encodeExpression :: Expr s Import -> Term
-encodeExpression e = encode (Dhall.Core.denote e :: Expr X Import)
+encodeExpression e = encode (Dhall.Core.denote e :: Expr Void Import)
 
 -- | Decode a Dhall expression from a CBOR `Term`
 decodeExpression :: FromTerm a => Term -> Either DecodingFailure (Expr s a)
diff --git a/src/Dhall/Core.hs b/src/Dhall/Core.hs
--- a/src/Dhall/Core.hs
+++ b/src/Dhall/Core.hs
@@ -4,9 +4,11 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE DeriveGeneric      #-}
 {-# LANGUAGE DeriveTraversable  #-}
+{-# LANGUAGE LambdaCase         #-}
 {-# LANGUAGE OverloadedStrings  #-}
 {-# LANGUAGE RankNTypes         #-}
 {-# LANGUAGE RecordWildCards    #-}
+{-# LANGUAGE StandaloneDeriving #-}
 {-# LANGUAGE UnicodeSyntax      #-}
 {-# OPTIONS_GHC -Wall #-}
 
@@ -29,7 +31,6 @@
     , URL(..)
     , Scheme(..)
     , Var(..)
-    , Binding(..)
     , Chunks(..)
     , Expr(..)
 
@@ -56,7 +57,15 @@
     -- * Optics
     , subExpressions
     , chunkExprs
+    , bindingExprs
 
+    -- * Let-blocks
+    , multiLet
+    , wrapInLets
+    , MultiLet(..)
+    , Binding(..)
+    , makeBinding
+
     -- * Miscellaneous
     , internalError
     , reservedIdentifiers
@@ -102,12 +111,13 @@
 import qualified Data.Char
 import {-# SOURCE #-} qualified Dhall.Eval
 import qualified Data.HashSet
+import qualified Data.List.NonEmpty
 import qualified Data.Sequence
 import qualified Data.Text
 import qualified Data.Text.Prettyprint.Doc  as Pretty
 import qualified Dhall.Map
 import qualified Dhall.Set
-import qualified Network.URI.Encode         as URI.Encode
+import qualified Network.URI                as URI
 import qualified Text.Printf
 
 
@@ -354,7 +364,20 @@
 instance Pretty Var where
     pretty = Pretty.unAnnotate . prettyVar
 
--- | Syntax tree for expressions
+{-| Syntax tree for expressions
+
+    The @s@ type parameter is used to track the presence or absence of `Src`
+    spans:
+
+    * If @s = `Src`@ then the code may contains `Src` spans (either in a `Noted`
+      constructor or inline within another constructor, like `Let`)
+    * If @s = `Void`@ then the code has no `Src` spans
+
+    The @a@ type parameter is used to track the presence or absence of imports
+
+    * If @a = `Import`@ then the code may contain unresolved `Import`s
+    * If @a = `Void`@ then the code has no `Import`s
+-}
 data Expr s a
     -- | > Const c                                  ~  c
     = Const Const
@@ -368,9 +391,23 @@
     | Pi  Text (Expr s a) (Expr s a)
     -- | > App f a                                  ~  f a
     | App (Expr s a) (Expr s a)
-    -- | > Let [Binding x Nothing  r] e             ~  let x     = r in e
-    --   > Let [Binding x (Just t) r] e             ~  let x : t = r in e
-    | Let (NonEmpty (Binding s a)) (Expr s a)
+    -- | > Let (Binding _ x _  Nothing  _ r) e      ~  let x     = r in e
+    --   > Let (Binding _ x _ (Just t ) _ r) e      ~  let x : t = r in e
+    --
+    -- The difference between
+    --
+    -- > let x = a    let y = b in e
+    --
+    -- and
+    --
+    -- > let x = a in let y = b in e
+    --
+    -- is only an additional 'Note' around @'Let' "y" …@ in the second
+    -- example.
+    --
+    -- See 'MultiLet' for a representation of let-blocks that mirrors the
+    -- source code more closely.
+    | Let (Binding s a) (Expr s a)
     -- | > Annot x t                                ~  x : t
     | Annot (Expr s a) (Expr s a)
     -- | > Bool                                     ~  Bool
@@ -405,6 +442,8 @@
     | NaturalToInteger
     -- | > NaturalShow                              ~  Natural/show
     | NaturalShow
+    -- | > NaturalSubtract                          ~  Natural/subtract
+    | NaturalSubtract
     -- | > NaturalPlus x y                          ~  x + y
     | NaturalPlus (Expr s a) (Expr s a)
     -- | > NaturalTimes x y                         ~  x * y
@@ -468,8 +507,6 @@
     | RecordLit (Map Text (Expr s a))
     -- | > Union        [(k1, Just t1), (k2, Nothing)] ~  < k1 : t1 | k2 >
     | Union     (Map Text (Maybe (Expr s a)))
-    -- | > UnionLit k v [(k1, Just t1), (k2, Nothing)] ~  < k = v | k1 : t1 | k2 >
-    | UnionLit Text (Expr s a) (Map Text (Maybe (Expr s a)))
     -- | > Combine x y                              ~  x ∧ y
     | Combine (Expr s a) (Expr s a)
     -- | > CombineTypes x y                         ~  x ⩓ y
@@ -487,16 +524,34 @@
     -- | > Project e (Left xs)                      ~  e.{ xs }
     -- | > Project e (Right t)                      ~  e.(t)
     | Project (Expr s a) (Either (Set Text) (Expr s a))
+    -- | > Assert e                                 ~  assert : e
+    | Assert (Expr s a)
+    -- | > Equivalent x y                           ~  x ≡ y
+    | Equivalent (Expr s a) (Expr s a)
     -- | > Note s x                                 ~  e
     | Note s (Expr s a)
     -- | > ImportAlt                                ~  e1 ? e2
     | ImportAlt (Expr s a) (Expr s a)
     -- | > Embed import                             ~  import
     | Embed a
-    deriving (Eq, Ord, Foldable, Generic, Traversable, Show, Data, NFData)
+    deriving (Foldable, Generic, Traversable, Show, Data, NFData)
 -- NB: If you add a constructor to Expr, please also update the Arbitrary
 -- instance in Dhall.Test.QuickCheck.
 
+-- | Note that this 'Eq' instance inherits `Double`'s defects, e.g.
+--
+-- >>> nan = 0/0
+-- >>> DoubleLit nan == DoubleLit nan
+-- False
+deriving instance (Eq s, Eq a) => Eq (Expr s a)
+
+-- | Note that this 'Eq' instance inherits `Double`'s defects, e.g.
+--
+-- >>> nan = 0/0
+-- >>> DoubleLit nan <= DoubleLit nan
+-- False
+deriving instance (Ord s, Ord a) => Ord (Expr s a)
+
 instance (Lift s, Lift a, Data s, Data a) => Lift (Expr s a)
 
 -- This instance is hand-written due to the fact that deriving
@@ -509,7 +564,7 @@
   fmap f (Lam v e1 e2) = Lam v (fmap f e1) (fmap f e2)
   fmap f (Pi v e1 e2) = Pi v (fmap f e1) (fmap f e2)
   fmap f (App e1 e2) = App (fmap f e1) (fmap f e2)
-  fmap f (Let as b) = Let (fmap (fmap f) as) (fmap f b)
+  fmap f (Let b e2) = Let (fmap f b) (fmap f e2)
   fmap f (Annot e1 e2) = Annot (fmap f e1) (fmap f e2)
   fmap _ Bool = Bool
   fmap _ (BoolLit b) = BoolLit b
@@ -527,6 +582,7 @@
   fmap _ NaturalOdd = NaturalOdd
   fmap _ NaturalToInteger = NaturalToInteger
   fmap _ NaturalShow = NaturalShow
+  fmap _ NaturalSubtract = NaturalSubtract
   fmap f (NaturalPlus e1 e2) = NaturalPlus (fmap f e1) (fmap f e2)
   fmap f (NaturalTimes e1 e2) = NaturalTimes (fmap f e1) (fmap f e2)
   fmap _ Integer = Integer
@@ -558,7 +614,6 @@
   fmap f (Record r) = Record (fmap (fmap f) r)
   fmap f (RecordLit r) = RecordLit (fmap (fmap f) r)
   fmap f (Union u) = Union (fmap (fmap (fmap f)) u)
-  fmap f (UnionLit v e u) = UnionLit v (fmap f e) (fmap (fmap (fmap f)) u)
   fmap f (Combine e1 e2) = Combine (fmap f e1) (fmap f e2)
   fmap f (CombineTypes e1 e2) = CombineTypes (fmap f e1) (fmap f e2)
   fmap f (Prefer e1 e2) = Prefer (fmap f e1) (fmap f e2)
@@ -566,6 +621,8 @@
   fmap f (ToMap e maybeE) = ToMap (fmap f e) (fmap (fmap f) maybeE)
   fmap f (Field e1 v) = Field (fmap f e1) v
   fmap f (Project e1 vs) = Project (fmap f e1) (fmap (fmap f) vs)
+  fmap f (Assert t) = Assert (fmap f t)
+  fmap f (Equivalent e1 e2) = Equivalent (fmap f e1) (fmap f e2)
   fmap f (Note s e1) = Note s (fmap f e1)
   fmap f (ImportAlt e1 e2) = ImportAlt (fmap f e1) (fmap f e2)
   fmap f (Embed a) = Embed (f a)
@@ -584,9 +641,12 @@
     Lam a b c            >>= k = Lam a (b >>= k) (c >>= k)
     Pi  a b c            >>= k = Pi a (b >>= k) (c >>= k)
     App a b              >>= k = App (a >>= k) (b >>= k)
-    Let as b             >>= k = Let (fmap f as) (b >>= k)
+    Let a b              >>= k = Let (adapt0 a) (b >>= k)
       where
-        f (Binding c d e) = Binding c (fmap (>>= k) d) (e >>= k)
+        adapt0 (Binding src0 c src1 d src2 e) =
+            Binding src0 c src1 (fmap adapt1 d) src2 (e >>= k)
+
+        adapt1 (src3, f) = (src3, f >>= k)
     Annot a b            >>= k = Annot (a >>= k) (b >>= k)
     Bool                 >>= _ = Bool
     BoolLit a            >>= _ = BoolLit a
@@ -604,6 +664,7 @@
     NaturalOdd           >>= _ = NaturalOdd
     NaturalToInteger     >>= _ = NaturalToInteger
     NaturalShow          >>= _ = NaturalShow
+    NaturalSubtract      >>= _ = NaturalSubtract
     NaturalPlus  a b     >>= k = NaturalPlus  (a >>= k) (b >>= k)
     NaturalTimes a b     >>= k = NaturalTimes (a >>= k) (b >>= k)
     Integer              >>= _ = Integer
@@ -635,7 +696,6 @@
     Record    a          >>= k = Record (fmap (>>= k) a)
     RecordLit a          >>= k = RecordLit (fmap (>>= k) a)
     Union     a          >>= k = Union (fmap (fmap (>>= k)) a)
-    UnionLit a b c       >>= k = UnionLit a (b >>= k) (fmap (fmap (>>= k)) c)
     Combine a b          >>= k = Combine (a >>= k) (b >>= k)
     CombineTypes a b     >>= k = CombineTypes (a >>= k) (b >>= k)
     Prefer a b           >>= k = Prefer (a >>= k) (b >>= k)
@@ -643,6 +703,8 @@
     ToMap a b            >>= k = ToMap (a >>= k) (fmap (>>= k) b)
     Field a b            >>= k = Field (a >>= k) b
     Project a b          >>= k = Project (a >>= k) (fmap (>>= k) b)
+    Assert a             >>= k = Assert (a >>= k)
+    Equivalent a b       >>= k = Equivalent (a >>= k) (b >>= k)
     Note a b             >>= k = Note a (b >>= k)
     ImportAlt a b        >>= k = ImportAlt (a >>= k) (b >>= k)
     Embed a              >>= k = k a
@@ -653,7 +715,7 @@
     first k (Lam a b c           ) = Lam a (first k b) (first k c)
     first k (Pi a b c            ) = Pi a (first k b) (first k c)
     first k (App a b             ) = App (first k a) (first k b)
-    first k (Let as b            ) = Let (fmap (first k) as) (first k b)
+    first k (Let a b             ) = Let (first k a) (first k b)
     first k (Annot a b           ) = Annot (first k a) (first k b)
     first _  Bool                  = Bool
     first _ (BoolLit a           ) = BoolLit a
@@ -671,6 +733,7 @@
     first _  NaturalOdd            = NaturalOdd
     first _  NaturalToInteger      = NaturalToInteger
     first _  NaturalShow           = NaturalShow
+    first _  NaturalSubtract       = NaturalSubtract
     first k (NaturalPlus a b     ) = NaturalPlus (first k a) (first k b)
     first k (NaturalTimes a b    ) = NaturalTimes (first k a) (first k b)
     first _  Integer               = Integer
@@ -702,13 +765,14 @@
     first k (Record a            ) = Record (fmap (first k) a)
     first k (RecordLit a         ) = RecordLit (fmap (first k) a)
     first k (Union a             ) = Union (fmap (fmap (first k)) a)
-    first k (UnionLit a b c      ) = UnionLit a (first k b) (fmap (fmap (first k)) c)
     first k (Combine a b         ) = Combine (first k a) (first k b)
     first k (CombineTypes a b    ) = CombineTypes (first k a) (first k b)
     first k (Prefer a b          ) = Prefer (first k a) (first k b)
     first k (Merge a b c         ) = Merge (first k a) (first k b) (fmap (first k) c)
     first k (ToMap a b           ) = ToMap (first k a) (fmap (first k) b)
     first k (Field a b           ) = Field (first k a) b
+    first k (Assert a            ) = Assert (first k a)
+    first k (Equivalent a b      ) = Equivalent (first k a) (first k b)
     first k (Project a b         ) = Project (first k a) (fmap (first k) b)
     first k (Note a b            ) = Note (k a) (first k b)
     first k (ImportAlt a b       ) = ImportAlt (first k a) (first k b)
@@ -719,19 +783,6 @@
 instance IsString (Expr s a) where
     fromString str = Var (fromString str)
 
-data Binding s a = Binding
-    { variable   :: Text
-    , annotation :: Maybe (Expr s a)
-    , value      :: Expr s a
-    } deriving (Functor, Foldable, Generic, Traversable, Show, Eq, Ord, Data, NFData)
-
-instance (Lift s, Lift a, Data s, Data a) => Lift (Binding s a)
-
-instance Bifunctor Binding where
-    first k (Binding a b c) = Binding a (fmap (first k) b) (first k c)
-
-    second = fmap
-
 -- | The body of an interpolated @Text@ literal
 data Chunks s a = Chunks [(Text, Expr s a)] Text
     deriving (Functor, Foldable, Generic, Traversable, Show, Eq, Ord, Data, NFData)
@@ -851,25 +902,15 @@
   where
     f' = shift d v f
     a' = shift d v a
-shift d (V x₀ n₀) (Let (Binding x₁ mA₀ a₀ :| []) b₀) =
-    Let (Binding x₁ mA₁ a₁ :| []) b₁
-  where
-    n₁ = if x₀ == x₁ then n₀ + 1 else n₀
-
-    mA₁ = fmap (shift d (V x₀ n₀)) mA₀
-    a₁  =       shift d (V x₀ n₀)   a₀
-
-    b₁  =       shift d (V x₀ n₁)   b₀
-shift d (V x₀ n₀) (Let (Binding x₁ mA₀ a₀ :| (l₀ : ls₀)) b₀) =
-    case shift d (V x₀ n₁) (Let (l₀ :| ls₀) b₀) of
-        Let (l₁ :| ls₁) b₁ -> Let (Binding x₁ mA₁ a₁ :| (l₁ : ls₁)) b₁
-        e                  -> Let (Binding x₁ mA₁ a₁ :|       []  ) e
+shift d (V x n) (Let (Binding src0 f src1 mt src2 r) e) =
+    Let (Binding src0 f src1 mt' src2 r') e'
   where
-    n₁ = if x₀ == x₁ then n₀ + 1 else n₀
-
-    mA₁ = fmap (shift d (V x₀ n₀)) mA₀
-    a₁  =       shift d (V x₀ n₀)   a₀
+    e' = shift d (V x n') e
+      where
+        n' = if x == f then n + 1 else n
 
+    mt' = fmap (fmap (shift d (V x n))) mt
+    r'  =             shift d (V x n)  r
 shift d v (Annot a b) = Annot a' b'
   where
     a' = shift d v a
@@ -906,6 +947,7 @@
 shift _ _ NaturalOdd = NaturalOdd
 shift _ _ NaturalToInteger = NaturalToInteger
 shift _ _ NaturalShow = NaturalShow
+shift _ _ NaturalSubtract = NaturalSubtract
 shift d v (NaturalPlus a b) = NaturalPlus a' b'
   where
     a' = shift d v a
@@ -962,10 +1004,6 @@
 shift d v (Union a) = Union a'
   where
     a' = fmap (fmap (shift d v)) a
-shift d v (UnionLit a b c) = UnionLit a b' c'
-  where
-    b' =             shift d v   b
-    c' = fmap (fmap (shift d v)) c
 shift d v (Combine a b) = Combine a' b'
   where
     a' = shift d v a
@@ -990,6 +1028,13 @@
 shift d v (Field a b) = Field a' b
   where
     a' = shift d v a
+shift d v (Assert a) = Assert a'
+  where
+    a' = shift d v a
+shift d v (Equivalent a b) = Equivalent a' b'
+  where
+    a' = shift d v a
+    b' = shift d v b
 shift d v (Project a b) = Project a' b'
   where
     a' =       shift d v  a
@@ -1026,29 +1071,15 @@
     f' = subst v e f
     a' = subst v e a
 subst v e (Var v') = if v == v' then e else Var v'
-subst (V x₀ n₀) e₀ (Let (Binding x₁ mA₀ a₀ :| []) b₀) =
-    Let (Binding x₁ mA₁ a₁ :| []) b₁
-  where
-    n₁ = if x₀ == x₁ then n₀ + 1 else n₀
-
-    e₁ = shift 1 (V x₁ 0) e₀
-
-    mA₁ = fmap (subst (V x₀ n₀) e₀) mA₀
-    a₁  =       subst (V x₀ n₀) e₀   a₀
-
-    b₁  =       subst (V x₀ n₁) e₁   b₀
-subst (V x₀ n₀) e₀ (Let (Binding x₁ mA₀ a₀ :| (l₀ : ls₀)) b₀) =
-    case subst (V x₀ n₁) e₁ (Let (l₀ :| ls₀) b₀) of
-        Let (l₁ :| ls₁) b₁ -> Let (Binding x₁ mA₁ a₁ :| (l₁ : ls₁)) b₁
-        e                  -> Let (Binding x₁ mA₁ a₁ :|       []  ) e
+subst (V x n) e (Let (Binding src0 f src1 mt src2 r) b) =
+    Let (Binding src0 f src1 mt' src2 r') b'
   where
-    n₁ = if x₀ == x₁ then n₀ + 1 else n₀
-
-    e₁ = shift 1 (V x₁ 0) e₀
-
-    mA₁ = fmap (subst (V x₀ n₀) e₀) mA₀
-    a₁  =       subst (V x₀ n₀) e₀   a₀
+    b' = subst (V x n') (shift 1 (V f 0) e) b
+      where
+        n' = if x == f then n + 1 else n
 
+    mt' = fmap (fmap (subst (V x n) e)) mt
+    r'  =             subst (V x n) e  r
 subst x e (Annot a b) = Annot a' b'
   where
     a' = subst x e a
@@ -1085,6 +1116,7 @@
 subst _ _ NaturalOdd = NaturalOdd
 subst _ _ NaturalToInteger = NaturalToInteger
 subst _ _ NaturalShow = NaturalShow
+subst _ _ NaturalSubtract = NaturalSubtract
 subst x e (NaturalPlus a b) = NaturalPlus a' b'
   where
     a' = subst x e a
@@ -1141,10 +1173,6 @@
 subst x e (Union kts) = Union kts'
   where
     kts' = fmap (fmap (subst x e)) kts
-subst x e (UnionLit a b kts) = UnionLit a b' kts'
-  where
-    b'   =             subst x e   b
-    kts' = fmap (fmap (subst x e)) kts
 subst x e (Combine a b) = Combine a' b'
   where
     a' = subst x e a
@@ -1173,6 +1201,13 @@
   where
     a' =       subst x e  a
     b' = fmap (subst x e) b
+subst x e (Assert a) = Assert a'
+  where
+    a' = subst x e a
+subst x e (Equivalent a b) = Equivalent a' b'
+  where
+    a' = subst x e a
+    b' = subst x e b
 subst x e (Note a b) = Note a b'
   where
     b' = subst x e b
@@ -1243,9 +1278,12 @@
 denote (Lam a b c           ) = Lam a (denote b) (denote c)
 denote (Pi a b c            ) = Pi a (denote b) (denote c)
 denote (App a b             ) = App (denote a) (denote b)
-denote (Let as b            ) = Let (fmap f as) (denote b)
+denote (Let a b             ) = Let (adapt0 a) (denote b)
   where
-    f (Binding c d e) = Binding c (fmap denote d) (denote e)
+    adapt0 (Binding _ c _ d _ e) =
+        Binding Nothing c Nothing (fmap adapt1 d) Nothing (denote e)
+
+    adapt1 (_, f) = (Nothing, denote f)
 denote (Annot a b           ) = Annot (denote a) (denote b)
 denote  Bool                  = Bool
 denote (BoolLit a           ) = BoolLit a
@@ -1263,6 +1301,7 @@
 denote  NaturalOdd            = NaturalOdd
 denote  NaturalToInteger      = NaturalToInteger
 denote  NaturalShow           = NaturalShow
+denote  NaturalSubtract       = NaturalSubtract
 denote (NaturalPlus a b     ) = NaturalPlus (denote a) (denote b)
 denote (NaturalTimes a b    ) = NaturalTimes (denote a) (denote b)
 denote  Integer               = Integer
@@ -1294,7 +1333,6 @@
 denote (Record a            ) = Record (fmap denote a)
 denote (RecordLit a         ) = RecordLit (fmap denote a)
 denote (Union a             ) = Union (fmap (fmap denote) a)
-denote (UnionLit a b c      ) = UnionLit a (denote b) (fmap (fmap denote) c)
 denote (Combine a b         ) = Combine (denote a) (denote b)
 denote (CombineTypes a b    ) = CombineTypes (denote a) (denote b)
 denote (Prefer a b          ) = Prefer (denote a) (denote b)
@@ -1302,6 +1340,8 @@
 denote (ToMap a b           ) = ToMap (denote a) (fmap denote b)
 denote (Field a b           ) = Field (denote a) b
 denote (Project a b         ) = Project (denote a) (fmap denote b)
+denote (Assert a            ) = Assert (denote a)
+denote (Equivalent a b      ) = Equivalent (denote a) (denote b)
 denote (ImportAlt a b       ) = ImportAlt (denote a) (denote b)
 denote (Embed a             ) = Embed a
 
@@ -1414,6 +1454,12 @@
                     App NaturalToInteger (NaturalLit n) -> pure (IntegerLit (toInteger n))
                     App NaturalShow (NaturalLit n) ->
                         pure (TextLit (Chunks [] (Data.Text.pack (show n))))
+                    App (App NaturalSubtract (NaturalLit x)) (NaturalLit y)
+                        | y >= x    -> pure (NaturalLit (subtract x y))
+                        | otherwise -> pure (NaturalLit 0)
+                    App (App NaturalSubtract (NaturalLit 0)) y -> pure y
+                    App (App NaturalSubtract _) (NaturalLit 0) -> pure (NaturalLit 0)
+                    App (App NaturalSubtract x) y | judgmentallyEqual x y -> pure (NaturalLit 0)
                     App IntegerShow (IntegerLit n)
                         | 0 <= n    -> pure (TextLit (Chunks [] ("+" <> Data.Text.pack (show n))))
                         | otherwise -> pure (TextLit (Chunks [] (Data.Text.pack (show n))))
@@ -1443,6 +1489,20 @@
                                 )
 
                         nil = ListLit (Just (App List _A₀)) empty
+                    App (App ListFold t) (ListLit _ xs) -> do
+                        t' <- loop t
+                        let list = Var (V "list" 0)
+                        let lam term =
+                                Lam "list" (Const Type)
+                                    (Lam "cons" (Pi "_" t' (Pi "_" list list))
+                                        (Lam "nil" list term))
+                        term <- foldrM
+                            (\x acc -> do
+                                x' <- loop x
+                                pure (App (App (Var (V "cons" 0)) x') acc))
+                            (Var (V "nil" 0))
+                            xs
+                        pure (lam term)
                     App (App (App (App (App ListFold _) (ListLit _ xs)) t) cons) nil -> do
                       t' <- loop t
                       if boundedType t' then strict else lazy
@@ -1487,14 +1547,23 @@
                             kvs = [ ("index", NaturalLit (fromIntegral n))
                                   , ("value", a_)
                                   ]
-                    App (App ListReverse t) (ListLit _ xs) ->
-                        loop (ListLit m (Data.Sequence.reverse xs))
-                      where
-                        m = if Data.Sequence.null xs then Just (App List t) else Nothing
-                    App (App (App (App (App OptionalFold _) (App None _)) _) _) nothing ->
-                        loop nothing
-                    App (App (App (App (App OptionalFold _) (Some x)) _) just) _ ->
-                        loop (App just x)
+                    App (App ListReverse _) (ListLit t xs) ->
+                        loop (ListLit t (Data.Sequence.reverse xs))
+
+                    App (App OptionalFold t0) x0 -> do
+                        t1 <- loop t0
+                        let optional = Var (V "optional" 0)
+                        let lam term = (Lam "optional"
+                                           (Const Type)
+                                           (Lam "some"
+                                               (Pi "_" t1 optional)
+                                               (Lam "none" optional term)))
+                        x1 <- loop x0
+                        pure $ case x1 of
+                            App None _ -> lam (Var (V "none" 0))
+                            Some x'    -> lam (App (Var (V "some" 0)) x')
+                            _          -> App (App OptionalFold t1) x1
+
                     App TextShow (TextLit (Chunks [] oldText)) ->
                         loop (TextLit (Chunks [] newText))
                       where
@@ -1504,18 +1573,11 @@
                         case res2 of
                             Nothing -> pure (App f' a')
                             Just app' -> loop app'
-    Let (Binding x _ a₀ :| ls₀) b₀ -> do
-        a₁ <- loop a₀
-
-        rest <- case ls₀ of
-                []       -> loop b₀
-                l₁ : ls₁ -> loop (Let (l₁ :| ls₁) b₀)
-
-        let a₂ = shift 1 (V x 0) a₁
-        let b₁ = subst (V x 0) a₂ rest
-        let b₂ = shift (-1) (V x 0) b₁
-
-        loop b₂
+    Let (Binding _ f _ _ _ r) b -> loop b''
+      where
+        r'  = shift   1  (V f 0) r
+        b'  = subst (V f 0) r' b
+        b'' = shift (-1) (V f 0) b'
     Annot x _ -> loop x
     Bool -> pure Bool
     BoolLit b -> pure (BoolLit b)
@@ -1568,6 +1630,7 @@
     NaturalOdd -> pure NaturalOdd
     NaturalToInteger -> pure NaturalToInteger
     NaturalShow -> pure NaturalShow
+    NaturalSubtract -> pure NaturalSubtract
     NaturalPlus x y -> decide <$> loop x <*> loop y
       where
         decide (NaturalLit 0)  r             = r
@@ -1642,10 +1705,6 @@
     Union kts -> Union . Dhall.Map.sort <$> kts'
       where
         kts' = traverse (traverse loop) kts
-    UnionLit k v kvs -> UnionLit k <$> v' <*> (Dhall.Map.sort <$> kvs')
-      where
-        v'   =                    loop  v
-        kvs' = traverse (traverse loop) kvs
     Combine x y -> decide <$> loop x <*> loop y
       where
         decide (RecordLit m) r | Data.Foldable.null m =
@@ -1653,7 +1712,7 @@
         decide l (RecordLit n) | Data.Foldable.null n =
             l
         decide (RecordLit m) (RecordLit n) =
-            RecordLit (Dhall.Map.sort (Dhall.Map.unionWith decide m n))
+            RecordLit (Dhall.Map.unionWith decide m n)
         decide l r =
             Combine l r
     CombineTypes x y -> decide <$> loop x <*> loop y
@@ -1663,7 +1722,7 @@
         decide l (Record n) | Data.Foldable.null n =
             l
         decide (Record m) (Record n) =
-            Record (Dhall.Map.sort (Dhall.Map.unionWith decide m n))
+            Record (Dhall.Map.unionWith decide m n)
         decide l r =
             CombineTypes l r
     Prefer x y -> decide <$> loop x <*> loop y
@@ -1673,7 +1732,9 @@
         decide l (RecordLit n) | Data.Foldable.null n =
             l
         decide (RecordLit m) (RecordLit n) =
-            RecordLit (Dhall.Map.sort (Dhall.Map.union n m))
+            RecordLit (Dhall.Map.union n m)
+        decide l r | judgmentallyEqual l r =
+            l
         decide l r =
             Prefer l r
     Merge x y t      -> do
@@ -1682,10 +1743,6 @@
         case x' of
             RecordLit kvsX ->
                 case y' of
-                    UnionLit kY vY _ ->
-                        case Dhall.Map.lookup kY kvsX of
-                            Just vX -> loop (App vX vY)
-                            Nothing -> Merge x' y' <$> t'
                     Field (Union ktsY) kY ->
                         case Dhall.Map.lookup kY ktsY of
                             Just Nothing ->
@@ -1731,12 +1788,27 @@
             _ -> do
                 return (ToMap x' t')
     Field r x        -> do
+        let singletonRecordLit v = RecordLit (Dhall.Map.singleton x v)
+
         r' <- loop r
         case r' of
             RecordLit kvs ->
                 case Dhall.Map.lookup x kvs of
-                    Just v  -> loop v
+                    Just v  -> pure v
                     Nothing -> Field <$> (RecordLit <$> traverse loop kvs) <*> pure x
+            Project r_ _ -> loop (Field r_ x)
+            Prefer (RecordLit kvs) r_ -> case Dhall.Map.lookup x kvs of
+                Just v -> pure (Field (Prefer (singletonRecordLit v) r_) x)
+                Nothing -> loop (Field r_ x)
+            Prefer l (RecordLit kvs) -> case Dhall.Map.lookup x kvs of
+                Just v -> pure v
+                Nothing -> loop (Field l x)
+            Combine (RecordLit kvs) r_ -> case Dhall.Map.lookup x kvs of
+                Just v -> pure (Field (Combine (singletonRecordLit v) r_) x)
+                Nothing -> loop (Field r_ x)
+            Combine l (RecordLit kvs) -> case Dhall.Map.lookup x kvs of
+                Just v -> pure (Field (Combine l (singletonRecordLit v)) x)
+                Nothing -> loop (Field l x)
             _ -> pure (Field r' x)
     Project r (Left xs)-> do
         r' <- loop r
@@ -1754,6 +1826,15 @@
             _ -> do
                 r' <- loop r
                 pure (Project r' (Right e2))
+    Assert t -> do
+        t' <- loop t
+
+        pure (Assert t')
+    Equivalent l r -> do
+        l' <- loop l
+        r' <- loop r
+
+        pure (Equivalent l' r')
     Note _ e' -> loop e'
     ImportAlt l _r -> loop l
     Embed a -> pure (Embed a)
@@ -1836,23 +1917,24 @@
           App NaturalEven (NaturalLit _) -> False
           App NaturalOdd (NaturalLit _) -> False
           App NaturalShow (NaturalLit _) -> False
+          App (App NaturalSubtract (NaturalLit _)) (NaturalLit _) -> False
+          App (App NaturalSubtract (NaturalLit 0)) _ -> False
+          App (App NaturalSubtract _) (NaturalLit 0) -> False
+          App (App NaturalSubtract x) y -> not (judgmentallyEqual x y)
           App NaturalToInteger (NaturalLit _) -> False
           App IntegerShow (IntegerLit _) -> False
           App IntegerToDouble (IntegerLit _) -> False
           App DoubleShow (DoubleLit _) -> False
           App (App OptionalBuild _) _ -> False
           App (App ListBuild _) _ -> False
-          App (App (App (App (App ListFold _) (ListLit _ _)) _) _) _ ->
-              False
+          App (App ListFold _) (ListLit _ _) -> False
           App (App ListLength _) (ListLit _ _) -> False
           App (App ListHead _) (ListLit _ _) -> False
           App (App ListLast _) (ListLit _ _) -> False
           App (App ListIndexed _) (ListLit _ _) -> False
           App (App ListReverse _) (ListLit _ _) -> False
-          App (App (App (App (App OptionalFold _) (Some _)) _) _) _ ->
-              False
-          App (App (App (App (App OptionalFold _) (App None _)) _) _) _ ->
-              False
+          App (App OptionalFold _) (Some _) -> False
+          App (App OptionalFold _) (App None _) -> False
           App TextShow (TextLit (Chunks [] _)) ->
               False
           _ -> True
@@ -1894,6 +1976,7 @@
       NaturalEven -> True
       NaturalOdd -> True
       NaturalShow -> True
+      NaturalSubtract -> True
       NaturalToInteger -> True
       NaturalPlus x y -> loop x && loop y && decide x y
         where
@@ -1948,7 +2031,6 @@
       Record kts -> Dhall.Map.isSorted kts && all loop kts
       RecordLit kvs -> Dhall.Map.isSorted kvs && all loop kvs
       Union kts -> Dhall.Map.isSorted kts && all (all loop) kts
-      UnionLit _ v kvs -> loop v && Dhall.Map.isSorted kvs && all (all loop) kvs
       Combine x y -> loop x && loop y && decide x y
         where
           decide (RecordLit m) _ | Data.Foldable.null m = False
@@ -1966,22 +2048,18 @@
           decide (RecordLit m) _ | Data.Foldable.null m = False
           decide _ (RecordLit n) | Data.Foldable.null n = False
           decide (RecordLit _) (RecordLit _) = False
-          decide  _ _ = True
-      Merge x y t -> loop x && loop y && all loop t &&
-          case x of
-              RecordLit kvsX ->
-                  case y of
-                      UnionLit kY _  _ ->
-                          case Dhall.Map.lookup kY kvsX of
-                              Just _  -> False
-                              Nothing -> True
-                      _ -> True
-              _ -> True
+          decide l r = not (judgmentallyEqual l r)
+      Merge x y t -> loop x && loop y && all loop t
       ToMap x t -> case x of
           RecordLit _ -> False
           _ -> loop x && all loop t
-      Field r _ -> case r of
+      Field r k -> case r of
           RecordLit _ -> False
+          Project _ _ -> False
+          Prefer (RecordLit m) _ -> Dhall.Map.keys m == [k] && loop r
+          Prefer _ (RecordLit _) -> False
+          Combine (RecordLit m) _ -> Dhall.Map.keys m == [k] && loop r
+          Combine _ (RecordLit m) -> Dhall.Map.keys m == [k] && loop r
           _ -> loop r
       Project r p -> loop r &&
           case p of
@@ -1991,8 +2069,10 @@
               Right e' -> case e' of
                   Record _ -> False
                   _ -> loop e'
+      Assert t -> loop t
+      Equivalent l r -> loop l && loop r
       Note _ e' -> loop e'
-      ImportAlt l _r -> loop l
+      ImportAlt _ _ -> False
       Embed _ -> True
 
 {-| Detect if the given variable is free within the given expression
@@ -2065,6 +2145,7 @@
         , "Natural/odd"
         , "Natural/toInteger"
         , "Natural/show"
+        , "Natural/subtract"
         , "Integer"
         , "Integer/show"
         , "Integer/toDouble"
@@ -2097,9 +2178,7 @@
 subExpressions f (Lam a b c) = Lam a <$> f b <*> f c
 subExpressions f (Pi a b c) = Pi a <$> f b <*> f c
 subExpressions f (App a b) = App <$> f a <*> f b
-subExpressions f (Let as b) = Let <$> traverse g as <*> f b
-  where
-    g (Binding c d e) = Binding c <$> traverse f d <*> f e
+subExpressions f (Let a b) = Let <$> bindingExprs f a <*> f b
 subExpressions f (Annot a b) = Annot <$> f a <*> f b
 subExpressions _ Bool = pure Bool
 subExpressions _ (BoolLit b) = pure (BoolLit b)
@@ -2117,6 +2196,7 @@
 subExpressions _ NaturalOdd = pure NaturalOdd
 subExpressions _ NaturalToInteger = pure NaturalToInteger
 subExpressions _ NaturalShow = pure NaturalShow
+subExpressions _ NaturalSubtract = pure NaturalSubtract
 subExpressions f (NaturalPlus a b) = NaturalPlus <$> f a <*> f b
 subExpressions f (NaturalTimes a b) = NaturalTimes <$> f a <*> f b
 subExpressions _ Integer = pure Integer
@@ -2149,8 +2229,6 @@
 subExpressions f (Record a) = Record <$> traverse f a
 subExpressions f ( RecordLit a ) = RecordLit <$> traverse f a
 subExpressions f (Union a) = Union <$> traverse (traverse f) a
-subExpressions f (UnionLit a b c) =
-    UnionLit a <$> f b <*> traverse (traverse f) c
 subExpressions f (Combine a b) = Combine <$> f a <*> f b
 subExpressions f (CombineTypes a b) = CombineTypes <$> f a <*> f b
 subExpressions f (Prefer a b) = Prefer <$> f a <*> f b
@@ -2158,6 +2236,8 @@
 subExpressions f (ToMap a t) = ToMap <$> f a <*> traverse f t
 subExpressions f (Field a b) = Field <$> f a <*> pure b
 subExpressions f (Project a b) = Project <$> f a <*> traverse f b
+subExpressions f (Assert a) = Assert <$> f a
+subExpressions f (Equivalent a b) = Equivalent <$> f a <*> f b
 subExpressions f (Note a b) = Note a <$> f b
 subExpressions f (ImportAlt l r) = ImportAlt <$> f l <*> f r
 subExpressions _ (Embed a) = pure (Embed a)
@@ -2196,11 +2276,8 @@
         "/\"" <> Pretty.pretty text <> "\""
 
 prettyURIComponent :: Text -> Doc ann
-prettyURIComponent text
-    | Data.Text.all (\c -> pathCharacter c && URI.Encode.isAllowed c) text =
-        "/" <> Pretty.pretty text
-    | otherwise =
-        "/\"" <> Pretty.pretty text <> "\""
+prettyURIComponent text =
+        Pretty.pretty $ URI.normalizeCase $ URI.normalizeEscape $ "/" <> Data.Text.unpack text
 
 {-| Convenience utility for converting `Either`-based exceptions to `IO`-based
     exceptions
@@ -2208,3 +2285,100 @@
 throws :: (Exception e, MonadIO io) => Either e a -> io a
 throws (Left  e) = liftIO (Control.Exception.throwIO e)
 throws (Right r) = return r
+
+{-
+Instead of converting explicitly between 'Expr's and 'MultiLet', it might
+be nicer to use a pattern synonym:
+
+> pattern MultiLet' :: NonEmpty (Binding s a) -> Expr s a -> Expr s a
+> pattern MultiLet' as b <- (multiLetFromExpr -> Just (MultiLet as b)) where
+>   MultiLet' as b = wrapInLets as b
+>
+> multiLetFromExpr :: Expr s a -> Maybe (MultiLet s a)
+> multiLetFromExpr = \case
+>     Let x mA a b -> Just (multiLet x mA a b)
+>     _ -> Nothing
+
+This works in principle, but GHC as of v8.8.1 doesn't handle it well:
+https://gitlab.haskell.org/ghc/ghc/issues/17096
+
+This should be fixed by GHC-8.10, so it might be worth revisiting then.
+-}
+
+{-| Generate a 'MultiLet' from the contents of a 'Let'.
+
+    In the resulting @'MultiLet' bs e@, @e@ is guaranteed not to be a 'Let',
+    but it might be a @('Note' … ('Let' …))@.
+
+    Given parser output, 'multiLet' consolidates @let@s that formed a
+    let-block in the original source.
+-}
+multiLet :: Binding s a -> Expr s a -> MultiLet s a
+multiLet b0 = \case
+    Let b1 e1 ->
+        let MultiLet bs e = multiLet b1 e1
+        in  MultiLet (Data.List.NonEmpty.cons b0 bs) e
+    e -> MultiLet (b0 :| []) e
+
+{-| Wrap let-'Binding's around an 'Expr'.
+
+'wrapInLets' can be understood as an inverse for 'multiLet':
+
+> let MultiLet bs e1 = multiLet b e0
+>
+> wrapInLets bs e1 == Let b e0
+-}
+wrapInLets :: Foldable f => f (Binding s a) -> Expr s a -> Expr s a
+wrapInLets bs e = foldr Let e bs
+
+data MultiLet s a = MultiLet (NonEmpty (Binding s a)) (Expr s a)
+
+{- | Record the binding part of a @let@ expression.
+
+For example,
+> let {- A -} x {- B -} : {- C -} Bool = {- D -} True in x
+will be instantiated as follows:
+
+* @bindingSrc0@ corresponds to the @A@ comment.
+* @variable@ is @"x"@
+* @bindingSrc1@ corresponds to the @B@ comment.
+* @annotation@ is 'Just' a pair, corresponding to the @C@ comment and @Bool@.
+* @bindingSrc2@ corresponds to the @D@ comment.
+* @value@ corresponds to @True@.
+-}
+data Binding s a = Binding
+    { bindingSrc0 :: Maybe s
+    , variable    :: Text
+    , bindingSrc1 :: Maybe s
+    , annotation  :: Maybe (Maybe s, Expr s a)
+    , bindingSrc2 :: Maybe s
+    , value       :: Expr s a
+    } deriving (Data, Eq, Foldable, Functor, Generic, NFData, Ord, Show, Traversable)
+
+instance Bifunctor Binding where
+    first k (Binding src0 a src1 b src2 c) =
+        Binding (fmap k src0) a (fmap k src1) (fmap adapt0 b) (fmap k src2) (first k c)
+      where
+        adapt0 (src3, d) = (fmap k src3, first k d)
+
+    second = fmap
+
+{-| Traverse over the immediate 'Expr' children in a 'Binding'.
+-}
+bindingExprs
+  :: (Applicative f)
+  => (Expr s a -> f (Expr s b))
+  -> Binding s a -> f (Binding s b)
+bindingExprs f (Binding s0 n s1 t s2 v) =
+  Binding
+    <$> pure s0
+    <*> pure n
+    <*> pure s1
+    <*> traverse (traverse f) t
+    <*> pure s2
+    <*> f v
+
+{-| Construct a 'Binding' with no source information and no type annotation.
+-}
+makeBinding :: Text -> Expr s a -> Binding s a
+makeBinding name = Binding Nothing name Nothing Nothing Nothing
diff --git a/src/Dhall/Diff.hs b/src/Dhall/Diff.hs
--- a/src/Dhall/Diff.hs
+++ b/src/Dhall/Diff.hs
@@ -12,19 +12,19 @@
 module Dhall.Diff (
     -- * Diff
       Diff (..)
-    , diffExpression
     , diffNormalized
-    , Dhall.Diff.diff
+    , diff
     ) where
 
 import Data.Foldable (fold, toList)
 import Data.List.NonEmpty (NonEmpty(..))
 import Data.Monoid (Any(..))
-import Data.Semigroup
+import Data.Semigroup hiding (diff)
 import Data.Sequence (Seq)
 import Data.String (IsString(..))
 import Data.Text (Text)
 import Data.Text.Prettyprint.Doc (Doc, Pretty)
+import Data.Void (Void)
 import Dhall.Core (Binding(..), Chunks (..), Const(..), Expr(..), Var(..))
 import Dhall.Binary (ToTerm)
 import Dhall.Map (Map)
@@ -153,18 +153,12 @@
 rparen = token Internal.rparen
 
 -- | Render the difference between the normal form of two expressions
-diffNormalized :: (Eq a, Pretty a, ToTerm a) => Expr s a -> Expr s a -> Doc Ann
+diffNormalized :: (Eq a, Pretty a, ToTerm a) => Expr s a -> Expr s a -> Diff
 diffNormalized l0 r0 = Dhall.Diff.diff l1 r1
   where
     l1 = Dhall.Core.alphaNormalize (Dhall.Core.normalize l0)
     r1 = Dhall.Core.alphaNormalize (Dhall.Core.normalize r0)
 
--- | Render the difference between two expressions
-diff :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Doc Ann
-diff l0 r0 = doc
-  where
-    Diff {..} = diffExpression l0 r0
-
 diffPrimitive :: Eq a => (a -> Diff) -> a -> a -> Diff
 diffPrimitive f l r
     | l == r    = ignore
@@ -210,7 +204,8 @@
 diffInt = diffPrimitive (token . Internal.prettyInt)
 
 diffVar :: Var -> Var -> Diff
-diffVar (V xL nL) (V xR nR) = format mempty label <> "@" <> natural
+diffVar (V xL nL) (V xR nR) =
+    format mempty label <> if same natural then mempty else "@" <> natural
   where
     label = diffLabel xL xR
 
@@ -255,10 +250,10 @@
 diffKeyVals
     :: (Eq a, Pretty a)
     => Diff
-    -> Map Text (Expr s a)
-    -> Map Text (Expr s a)
+    -> Map Text (Expr Void a)
+    -> Map Text (Expr Void a)
     -> [Diff]
-diffKeyVals assign = diffKeysWith assign diffExpression
+diffKeyVals assign = diffKeysWith assign diff
 
 diffKeysWith
     :: Diff
@@ -311,15 +306,8 @@
 bracketed = enclosed (lbracket <> " ") (comma <> " ") rbracket
 
 diffText :: Text -> Text -> Diff
-diffText l r
-  | null parts         = "\"\""
-  | allDifferent parts = difference textSkeleton textSkeleton
-  | allSame parts      = textSkeleton
-  | otherwise          = "\"" <> foldMap prettyPart parts <> "\""
+diffText l r = "\"" <> foldMap prettyPart parts <> "\""
   where
-    allDifferent = not . any isBoth
-    allSame      = all isBoth
-
     -- TODO: check for color support from the TTY
     colorDiff colorCode chars =
             "\ESC["
@@ -349,7 +337,7 @@
 
 diffChunks
     :: (Eq a, Pretty a)
-    => Chunks s a -> Chunks s a -> Diff
+    => Chunks Void a -> Chunks Void a -> Diff
 diffChunks cL cR
   | null chunks             = "\"\""
   | [c] <- chunks           = c
@@ -365,21 +353,17 @@
     chunkDiff a b =
       case (a, b) of
         (Left  x, Left y ) -> diffText x y
-        (Right x, Right y) -> diffExpression x y
+        (Right x, Right y) -> diff x y
         _                  -> diffTextSkeleton
 
 diffList
     :: (Eq a, Pretty a)
-    => Seq (Expr s a) -> Seq (Expr s a) -> Diff
-diffList l r
-  | allDifferent parts = difference listSkeleton listSkeleton
-  | otherwise          = bracketed (foldMap diffPart parts)
+    => Seq (Expr Void a) -> Seq (Expr Void a) -> Diff
+diffList l r = bracketed (foldMap diffPart parts)
   where
-    allDifferent = any (not . isBoth)
-
     -- Sections of the list that are only in left, only in right, or in both
     parts =
-        Algo.Diff.getGroupedDiffBy ((same .) . diffExpression) (toList l) (toList r)
+        Algo.Diff.getGroupedDiffBy ((same .) . diff) (toList l) (toList r)
 
     -- Render each element of a list using an extra rendering function f
     prettyElems f = map (f . token . Internal.prettyExpr)
@@ -398,58 +382,22 @@
         Algo.Diff.Both _ _        ->
             pure ignore
 
--- Helper function to check when a diff part is present on both sides
-isBoth :: Algo.Diff.Diff a -> Bool
-isBoth p
-  | Algo.Diff.Both _ _ <- p = True
-  | otherwise               = False
-
 diffRecord
     :: (Eq a, Pretty a)
-    => Map Text (Expr s a) -> Map Text (Expr s a) -> Diff
+    => Map Text (Expr Void a) -> Map Text (Expr Void a) -> Diff
 diffRecord kvsL kvsR = braced (diffKeyVals colon kvsL kvsR)
 
 diffRecordLit
     :: (Eq a, Pretty a)
-    => Map Text (Expr s a) -> Map Text (Expr s a) -> Diff
+    => Map Text (Expr Void a) -> Map Text (Expr Void a) -> Diff
 diffRecordLit kvsL kvsR = braced (diffKeyVals equals kvsL kvsR)
 
 diffUnion
     :: (Eq a, Pretty a)
-    => Map Text (Maybe (Expr s a)) -> Map Text (Maybe (Expr s a)) -> Diff
+    => Map Text (Maybe (Expr Void a)) -> Map Text (Maybe (Expr Void a)) -> Diff
 diffUnion kvsL kvsR = angled (diffKeysWith colon diffVals kvsL kvsR)
   where
-    diffVals = diffMaybe (colon <> " ") diffExpression
-
-diffUnionLit
-    :: (Eq a, Pretty a)
-    => Text
-    -> Text
-    -> Expr s a
-    -> Expr s a
-    -> Map Text (Maybe (Expr s a))
-    -> Map Text (Maybe (Expr s a))
-    -> Diff
-diffUnionLit kL kR vL vR kvsL kvsR =
-        langle
-    <>  " "
-    <>  format " " (diffLabel kL kR)
-    <>  equals
-    <>  " "
-    <>  format " " (diffExpression vL vR)
-    <>  halfAngled (diffKeysWith colon diffVals kvsL kvsR)
-  where
-    diffVals = diffMaybe (colon <> " ") diffExpression
-
-    halfAngled = enclosed (pipe <> " ") (pipe <> " ") rangle
-
-listSkeleton :: Diff
-listSkeleton =
-        lbracket
-    <>  " "
-    <>  ignore
-    <>  " "
-    <>  rbracket
+    diffVals = diffMaybe (colon <> " ") diff
 
 textSkeleton :: Diff
 textSkeleton =
@@ -567,12 +515,20 @@
     <>  operator "++"
     <>  " "
     <>  ignore
-skeleton (ListLit {}) =
-        listSkeleton
-    <>  " "
-    <>  colon
-    <>  " "
-    <>  ignore
+skeleton (ListLit _ elems)
+    | null elems =
+            lbracket
+        <>  rbracket
+        <>  " "
+        <>  colon
+        <>  " "
+        <>  ignore
+    | otherwise =
+            lbracket
+        <>  " "
+        <>  ignore
+        <>  " "
+        <>  rbracket
 skeleton (ListAppend {}) =
         ignore
     <>  " "
@@ -609,16 +565,6 @@
     <>  ignore
     <>  " "
     <>  rangle
-skeleton (UnionLit {}) =
-        langle
-    <>  " "
-    <>  ignore
-    <>  " "
-    <>  equals
-    <>  " "
-    <>  ignore
-    <>  " "
-    <>  rangle
 skeleton (Combine {}) =
         ignore
     <>  " "
@@ -664,8 +610,9 @@
 mismatch :: Pretty a => Expr s a -> Expr s a -> Diff
 mismatch l r = difference (skeleton l) (skeleton r)
 
-diffExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
-diffExpression l@(Lam {}) r@(Lam {}) =
+-- | Render the difference between two expressions
+diff :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
+diff l@(Lam {}) r@(Lam {}) =
     enclosed' "  " (rarrow <> " ") (docs l r)
   where
     docs (Lam aL bL cL) (Lam aR bR cR) =
@@ -676,16 +623,16 @@
             <>  format " " (diffLabel aL aR)
             <>  colon
             <>  " "
-            <>  format mempty (diffExpression bL bR)
+            <>  format mempty (diff bL bR)
             <>  rparen
 
     docs aL aR =
-        pure (diffExpression aL aR)
-diffExpression l@(Lam {}) r =
+        pure (diff aL aR)
+diff l@(Lam {}) r =
     mismatch l r
-diffExpression l r@(Lam {}) =
+diff l r@(Lam {}) =
     mismatch l r
-diffExpression l@(BoolIf {}) r@(BoolIf {}) =
+diff l@(BoolIf {}) r@(BoolIf {}) =
     enclosed' "      " (keyword "else" <> "  ") (docs l r)
   where
     docs (BoolIf aL bL cL) (BoolIf aR bR cR) =
@@ -693,64 +640,77 @@
       where
         doc =   keyword "if"
             <>  " "
-            <>  format " " (diffExpression aL aR)
+            <>  format " " (diff aL aR)
             <>  keyword "then"
             <>  " "
-            <>  diffExpression bL bR
+            <>  diff bL bR
     docs aL aR =
-        pure (diffExpression aL aR)
-diffExpression l@(BoolIf {}) r =
+        pure (diff aL aR)
+diff l@(BoolIf {}) r =
     mismatch l r
-diffExpression l r@(BoolIf {}) =
+diff l r@(BoolIf {}) =
     mismatch l r
-diffExpression (Let asL bL ) (Let asR bR) =
-    enclosed' "" (keyword "in" <> "  ")
-        (Data.List.NonEmpty.zipWith docA asL asR <> pure docB)
+diff l@(Let {}) r@(Let {}) =
+    enclosed' "    " (keyword "in" <> "  ") (docs l r)
   where
-    docA (Binding cL dL eL) (Binding cR dR eR) = align doc
+    docs (Let (Binding _ aL _ bL _ cL) dL) (Let (Binding _ aR _ bR _ cR) dR) =
+        Data.List.NonEmpty.cons (align doc) (docs dL dR)
       where
+        bL' = fmap snd bL
+        bR' = fmap snd bR
+
         doc =   keyword "let"
             <>  " "
-            <>  format " " (diffLabel cL cR)
-            <>  format " " (diffMaybe (colon <> " ") diffExpression dL dR)
+            <>  format " " (diffLabel aL aR)
+            <>  format " " (diffMaybe (colon <> " ") diff bL' bR')
             <>  equals
             <>  " "
-            <>  diffExpression eL eR
-
-    docB = diffExpression bL bR
-diffExpression l@(Let {}) r =
+            <>  diff cL cR
+    docs aL aR = pure (diff aL aR)
+diff l@(Let {}) r =
     mismatch l r
-diffExpression l r@(Let {}) =
+diff l r@(Let {}) =
     mismatch l r
-diffExpression l@(Pi {}) r@(Pi {}) =
+diff l@(Pi {}) r@(Pi {}) =
     enclosed' "  " (rarrow <> " ") (docs l r)
   where
     docs (Pi aL bL cL) (Pi aR bR cR) =
         Data.List.NonEmpty.cons (align doc) (docs cL cR)
       where
         doc | same docA && same docB = ignore
+            | same docA =
+                format mempty docB
             | otherwise =
-                forall
-            <>  lparen
-            <>  format " " docA
-            <>  colon
-            <>  " "
-            <>  format mempty docB
-            <>  rparen
+                    forall
+                <>  lparen
+                <>  format " " docA
+                <>  colon
+                <>  " "
+                <>  format mempty docB
+                <>  rparen
           where
             docA = diffLabel aL aR
 
-            docB = diffExpression bL bR
+            docB = diff bL bR
 
-    docs aL aR = pure (diffExpression aL aR)
-diffExpression l@(Pi {}) r =
+    docs aL aR = pure (diff aL aR)
+diff l@(Pi {}) r =
     mismatch l r
-diffExpression l r@(Pi {}) =
+diff l r@(Pi {}) =
     mismatch l r
-diffExpression l r =
+diff (Assert aL) (Assert aR) =
+    align
+        (  "  " <> keyword "assert"
+        <> hardline <> colon <> " " <> diff aL aR
+        )
+diff l@(Assert {}) r =
+    mismatch l r
+diff l r@(Assert {}) =
+    mismatch l r
+diff l r =
     diffAnnotatedExpression l r
 
-diffAnnotatedExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffAnnotatedExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffAnnotatedExpression (Merge aL bL cL) (Merge aR bR cR) = align doc
   where
     doc =   keyword "merge"
@@ -788,7 +748,7 @@
       where
         doc = diffOperatorExpression aL aR
     docs aL aR =
-        diffExpression aL aR :| []
+        diff aL aR :| []
 diffAnnotatedExpression l@(Annot {}) r =
     mismatch l r
 diffAnnotatedExpression l r@(Annot {}) =
@@ -796,17 +756,47 @@
 diffAnnotatedExpression l r =
     diffOperatorExpression l r
 
-diffOperatorExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
-diffOperatorExpression = diffOrExpression
+{- Whitespace in diffs of operator expressions:
 
-diffOrExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+All indentation (whether pretty-printing or diffing) is a multiple of two
+spaces, so if the operator is one character long (like ?) then the diff pads
+the left margin to two space:
+
+    ␣␣e₀
+    ?␣e₁
+
+... but if the operator is two characters long (like ||) then the diff pads
+the left margin to four spaces:
+
+     ␣␣␣␣e₀
+     ||␣␣e₁
+-}
+diffOperatorExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
+diffOperatorExpression = diffImportAltExpression
+
+diffImportAltExpression :: (Pretty a, Eq a) => Expr Void a -> Expr Void a -> Diff
+diffImportAltExpression l@(ImportAlt {}) r@(ImportAlt {}) =
+    enclosed' "  " (operator "?" <> " ") (docs l r)
+  where
+    docs (ImportAlt aL bL) (ImportAlt aR bR) =
+        Data.List.NonEmpty.cons (diffOrExpression aL aR) (docs bL bR)
+    docs aL aR =
+        pure (diffOrExpression aL aR)
+diffImportAltExpression l@(ImportAlt {}) r =
+    mismatch l r
+diffImportAltExpression l r@(ImportAlt {}) =
+    mismatch l r
+diffImportAltExpression l r =
+    diffOrExpression l r
+
+diffOrExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffOrExpression l@(BoolOr {}) r@(BoolOr {}) =
     enclosed' "    " (operator "||" <> "  ") (docs l r)
   where
     docs (BoolOr aL bL) (BoolOr aR bR) =
-        Data.List.NonEmpty.cons (diffTextAppendExpression aL aR) (docs bL bR)
+        Data.List.NonEmpty.cons (diffPlusExpression aL aR) (docs bL bR)
     docs aL aR =
-        pure (diffTextAppendExpression aL aR)
+        pure (diffPlusExpression aL aR)
 diffOrExpression l@(BoolOr {}) r =
     mismatch l r
 diffOrExpression l r@(BoolOr {}) =
@@ -814,14 +804,14 @@
 diffOrExpression l r =
     diffPlusExpression l r
 
-diffPlusExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffPlusExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffPlusExpression l@(NaturalPlus {}) r@(NaturalPlus {}) =
     enclosed' "  " (operator "+" <> " ") (docs l r)
   where
     docs (NaturalPlus aL bL) (NaturalPlus aR bR) =
-        Data.List.NonEmpty.cons (diffListAppendExpression aL aR) (docs bL bR)
+        Data.List.NonEmpty.cons (diffTextAppendExpression aL aR) (docs bL bR)
     docs aL aR =
-        pure (diffListAppendExpression aL aR)
+        pure (diffTextAppendExpression aL aR)
 diffPlusExpression l@(NaturalPlus {}) r =
     mismatch l r
 diffPlusExpression l r@(NaturalPlus {}) =
@@ -829,14 +819,14 @@
 diffPlusExpression l r =
     diffTextAppendExpression l r
 
-diffTextAppendExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffTextAppendExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffTextAppendExpression l@(TextAppend {}) r@(TextAppend {}) =
     enclosed' "    " (operator "++" <> "  ") (docs l r)
   where
     docs (TextAppend aL bL) (TextAppend aR bR) =
-        Data.List.NonEmpty.cons (diffPlusExpression aL aR) (docs bL bR)
+        Data.List.NonEmpty.cons (diffListAppendExpression aL aR) (docs bL bR)
     docs aL aR =
-        pure (diffPlusExpression aL aR)
+        pure (diffListAppendExpression aL aR)
 diffTextAppendExpression l@(TextAppend {}) r =
     mismatch l r
 diffTextAppendExpression l r@(TextAppend {}) =
@@ -844,7 +834,7 @@
 diffTextAppendExpression l r =
     diffListAppendExpression l r
 
-diffListAppendExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffListAppendExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffListAppendExpression l@(ListAppend {}) r@(ListAppend {}) =
     enclosed' "  " (operator "#" <> " ") (docs l r)
   where
@@ -859,7 +849,7 @@
 diffListAppendExpression l r =
     diffAndExpression l r
 
-diffAndExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffAndExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffAndExpression l@(BoolAnd {}) r@(BoolAnd {}) =
     enclosed' "    " (operator "&&" <> "  ") (docs l r)
   where
@@ -874,7 +864,7 @@
 diffAndExpression l r =
     diffCombineExpression l r
 
-diffCombineExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffCombineExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffCombineExpression l@(Combine {}) r@(Combine {}) =
     enclosed' "  " (operator "∧" <> " ") (docs l r)
   where
@@ -889,7 +879,7 @@
 diffCombineExpression l r =
     diffPreferExpression l r
 
-diffPreferExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffPreferExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffPreferExpression l@(Prefer {}) r@(Prefer {}) =
     enclosed' "  " (operator "⫽" <> " ") (docs l r)
   where
@@ -904,7 +894,7 @@
 diffPreferExpression l r =
     diffCombineTypesExpression l r
 
-diffCombineTypesExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffCombineTypesExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffCombineTypesExpression l@(CombineTypes {}) r@(CombineTypes {}) =
     enclosed' "  " (operator "*" <> " ") (docs l r)
   where
@@ -919,7 +909,7 @@
 diffCombineTypesExpression l r =
     diffTimesExpression l r
 
-diffTimesExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffTimesExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffTimesExpression l@(NaturalTimes {}) r@(NaturalTimes {}) =
     enclosed' "  " (operator "*" <> " ") (docs l r)
   where
@@ -934,7 +924,7 @@
 diffTimesExpression l r =
     diffEqualExpression l r
 
-diffEqualExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffEqualExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffEqualExpression l@(BoolEQ {}) r@(BoolEQ {}) =
     enclosed' "    " (operator "==" <> "  ") (docs l r)
   where
@@ -949,22 +939,38 @@
 diffEqualExpression l r =
     diffNotEqualExpression l r
 
-diffNotEqualExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffNotEqualExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffNotEqualExpression l@(BoolNE {}) r@(BoolNE {}) =
     enclosed' "    " (operator "!=" <> "  ") (docs l r)
   where
     docs (BoolNE aL bL) (BoolNE aR bR) =
-        Data.List.NonEmpty.cons (diffApplicationExpression aL aR) (docs bL bR)
+        Data.List.NonEmpty.cons (diffEquivalentExpression aL aR) (docs bL bR)
     docs aL aR =
-        pure (diffApplicationExpression aL aR)
+        pure (diffEquivalentExpression aL aR)
 diffNotEqualExpression l@(BoolNE {}) r =
     mismatch l r
 diffNotEqualExpression l r@(BoolNE {}) =
     mismatch l r
 diffNotEqualExpression l r =
+    diffEquivalentExpression l r
+
+diffEquivalentExpression
+    :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
+diffEquivalentExpression l@(Equivalent {}) r@(Equivalent {}) =
+    enclosed' "  " (operator "≡" <> " ") (docs l r)
+  where
+    docs (Equivalent aL bL) (Equivalent aR bR) =
+        Data.List.NonEmpty.cons (diffApplicationExpression aL aR) (docs bL bR)
+    docs aL aR =
+        pure (diffApplicationExpression aL aR)
+diffEquivalentExpression l@(Equivalent {}) r =
+    mismatch l r
+diffEquivalentExpression l r@(Equivalent {}) =
+    mismatch l r
+diffEquivalentExpression l r =
     diffApplicationExpression l r
 
-diffApplicationExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffApplicationExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffApplicationExpression l@(App {}) r@(App {}) =
     enclosed' mempty mempty (Data.List.NonEmpty.reverse (docs l r))
   where
@@ -991,7 +997,7 @@
 diffApplicationExpression l r =
     diffImportExpression l r
 
-diffImportExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffImportExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffImportExpression (Embed l) (Embed r) =
     diffPretty l r
 diffImportExpression l@(Embed {}) r =
@@ -1001,7 +1007,7 @@
 diffImportExpression l r =
     diffSelectorExpression l r
 
-diffSelectorExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffSelectorExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffSelectorExpression l@(Field {}) r@(Field {}) =
     enclosed' "  " (dot <> " ") (Data.List.NonEmpty.reverse (docs l r))
   where
@@ -1010,7 +1016,7 @@
     docs (Project aL (Left bL)) (Project aR (Left bR)) =
         Data.List.NonEmpty.cons (diffLabels bL bR) (docs aL aR)
     docs (Project aL (Right bL)) (Project aR (Right bR)) =
-        Data.List.NonEmpty.cons (diffExpression bL bR) (docs aL aR)
+        Data.List.NonEmpty.cons (diff bL bR) (docs aL aR)
     docs aL aR =
         pure (diffPrimitiveExpression aL aR)
 diffSelectorExpression l@(Field {}) r =
@@ -1025,7 +1031,7 @@
     docs (Project aL (Left bL)) (Project aR (Left bR)) =
         Data.List.NonEmpty.cons (diffLabels bL bR) (docs aL aR)
     docs (Project aL (Right bL)) (Project aR (Right bR)) =
-        Data.List.NonEmpty.cons (diffExpression bL bR) (docs aL aR)
+        Data.List.NonEmpty.cons (diff bL bR) (docs aL aR)
     docs aL aR =
         pure (diffPrimitiveExpression aL aR)
 diffSelectorExpression l@(Project {}) r =
@@ -1035,7 +1041,7 @@
 diffSelectorExpression l r =
     diffPrimitiveExpression l r
 
-diffPrimitiveExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff
+diffPrimitiveExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
 diffPrimitiveExpression (Var aL) (Var aR) =
     diffVar aL aR
 diffPrimitiveExpression l@(Var {}) r =
@@ -1102,6 +1108,12 @@
     mismatch l r
 diffPrimitiveExpression l r@NaturalShow =
     mismatch l r
+diffPrimitiveExpression NaturalSubtract NaturalSubtract =
+    "…"
+diffPrimitiveExpression l@NaturalSubtract r =
+    mismatch l r
+diffPrimitiveExpression l r@NaturalSubtract =
+    mismatch l r
 diffPrimitiveExpression Integer Integer =
     "…"
 diffPrimitiveExpression l@Integer r =
@@ -1267,15 +1279,9 @@
     mismatch l r
 diffPrimitiveExpression l r@(Union {}) =
     mismatch l r
-diffPrimitiveExpression (UnionLit aL bL cL) (UnionLit aR bR cR) =
-    diffUnionLit aL aR bL bR cL cR
-diffPrimitiveExpression l@(UnionLit {}) r =
-    mismatch l r
-diffPrimitiveExpression l r@(UnionLit {}) =
-    mismatch l r
 diffPrimitiveExpression aL aR =
     if same doc
     then ignore
     else align ("( " <> doc <> hardline <> ")")
   where
-    doc = diffExpression aL aR
+    doc = diff aL aR
diff --git a/src/Dhall/Eval.hs b/src/Dhall/Eval.hs
--- a/src/Dhall/Eval.hs
+++ b/src/Dhall/Eval.hs
@@ -58,15 +58,15 @@
 import Control.Applicative (Applicative(..), (<$>))
 #endif
 
-import Data.Foldable (foldr', foldl', toList)
-import Data.List.NonEmpty (NonEmpty(..), cons)
+import Data.Foldable (foldr', toList)
 import Data.Semigroup (Semigroup(..))
 import Data.Sequence (Seq)
 import Data.Text (Text)
+import Data.Void (Void)
 
 import Dhall.Core (
-    Expr(..)
-  , Binding(..)
+    Binding(..)
+  , Expr(..)
   , Chunks(..)
   , Const(..)
   , Import
@@ -78,12 +78,11 @@
 -- import Dhall.Import.Types (InternalError)
 import Dhall.Map (Map)
 import Dhall.Set (Set)
-import Dhall.X   (X)
 import GHC.Natural (Natural)
 import Unsafe.Coerce (unsafeCoerce)
 
+import qualified Codec.Serialise     as Serialise
 import qualified Data.Char
-import qualified Data.List.NonEmpty
 import qualified Data.Sequence
 import qualified Data.Text
 import qualified Dhall.Binary
@@ -98,8 +97,6 @@
   | Skip !(Env a) {-# unpack #-} !Text
   | Extend !(Env a) {-# unpack #-} !Text (Val a)
 
-data Void
-
 coeExprVoid :: Expr Void a -> Expr s a
 coeExprVoid = unsafeCoerce
 {-# inline coeExprVoid #-}
@@ -140,6 +137,7 @@
   | NaturalFoldCl (Val a)
   | ListFoldCl (Val a)
   | OptionalFoldCl (Val a)
+  | NaturalSubtractZero
 
 pattern VPrim :: (Val a -> Val a) -> Val a
 pattern VPrim f = VHLam Prim f
@@ -173,6 +171,7 @@
   | VNaturalOdd !(Val a)
   | VNaturalToInteger !(Val a)
   | VNaturalShow !(Val a)
+  | VNaturalSubtract !(Val a) !(Val a)
   | VNaturalPlus !(Val a) !(Val a)
   | VNaturalTimes !(Val a) !(Val a)
 
@@ -209,7 +208,6 @@
   | VRecord !(Map Text (Val a))
   | VRecordLit !(Map Text (Val a))
   | VUnion !(Map Text (Maybe (Val a)))
-  | VUnionLit !Text !(Val a) !(Map Text (Maybe (Val a)))
   | VCombine !(Val a) !(Val a)
   | VCombineTypes !(Val a) !(Val a)
   | VPrefer !(Val a) !(Val a)
@@ -218,6 +216,8 @@
   | VField !(Val a) !Text
   | VInject !(Map Text (Maybe (Val a))) !Text !(Maybe (Val a))
   | VProject !(Val a) !(Either (Set Text) (Val a))
+  | VAssert !(Val a)
+  | VEquivalent !(Val a) !(Val a)
   | VEmbed a
 
 vFun :: Val a -> Val a -> Val a
@@ -273,14 +273,14 @@
 vCombine t u = case (t, u) of
   (VRecordLit m, u) | null m    -> u
   (t, VRecordLit m) | null m    -> t
-  (VRecordLit m, VRecordLit m') -> VRecordLit (Dhall.Map.sort (Dhall.Map.unionWith vCombine m m'))
+  (VRecordLit m, VRecordLit m') -> VRecordLit (Dhall.Map.unionWith vCombine m m')
   (t, u)                        -> VCombine t u
 
 vCombineTypes :: Val a -> Val a -> Val a
 vCombineTypes t u = case (t, u) of
   (VRecord m, u) | null m -> u
   (t, VRecord m) | null m -> t
-  (VRecord m, VRecord m') -> VRecord (Dhall.Map.sort (Dhall.Map.unionWith vCombineTypes m m'))
+  (VRecord m, VRecord m') -> VRecord (Dhall.Map.unionWith vCombineTypes m m')
   (t, u)                  -> VCombineTypes t u
 
 vListAppend :: Val a -> Val a -> Val a
@@ -299,6 +299,34 @@
   (t,             u            ) -> VNaturalPlus t u
 {-# inline vNaturalPlus #-}
 
+vField :: Val a -> Text -> Val a
+vField t0 k = go t0 where
+  go = \case
+    VUnion m -> case Dhall.Map.lookup k m of
+      Just (Just _) -> VPrim $ \ ~u -> VInject m k (Just u)
+      Just Nothing  -> VInject m k Nothing
+      _             -> error errorMsg
+    VRecordLit m
+      | Just v <- Dhall.Map.lookup k m -> v
+      | otherwise -> error errorMsg
+    VProject t _ -> go t
+    VPrefer (VRecordLit m) r -> case Dhall.Map.lookup k m of
+      Just v -> VField (VPrefer (singletonVRecordLit v) r) k
+      Nothing -> go r
+    VPrefer l (VRecordLit m) -> case Dhall.Map.lookup k m of
+      Just v -> v
+      Nothing -> go l
+    VCombine (VRecordLit m) r -> case Dhall.Map.lookup k m of
+      Just v -> VField (VCombine (singletonVRecordLit v) r) k
+      Nothing -> go r
+    VCombine l (VRecordLit m) -> case Dhall.Map.lookup k m of
+      Just v -> VField (VCombine l (singletonVRecordLit v)) k
+      Nothing -> go l
+    t -> VField t k
+
+  singletonVRecordLit v = VRecordLit (Dhall.Map.singleton k v)
+{-# inline vField #-}
+
 eval :: forall a. Eq a => Env a -> Expr Void a -> Val a
 eval !env t =
   let
@@ -322,10 +350,9 @@
     Lam x a t        -> VLam (evalE a) (Cl x env t)
     Pi x a b         -> VPi (evalE a) (Cl x env b)
     App t u          -> vApp (evalE t) (evalE u)
-    Let (b :| bs) t  -> go env (b:bs) where
-                          go !env []     = eval env t
-                          go  env (b:bs) = go (Extend env (variable b)
-                                                          (eval env (value b))) bs
+    Let (Binding _ x _ _mA _ a) b ->
+                        let !env' = Extend env x (evalE a)
+                        in eval env' b
     Annot t _        -> evalE t
 
     Bool             -> VBool
@@ -392,6 +419,20 @@
                                       n             -> VNaturalToInteger n
     NaturalShow      -> VPrim $ \case VNaturalLit n -> VTextLit (VChunks [] (Data.Text.pack (show n)))
                                       n             -> VNaturalShow n
+    NaturalSubtract -> VPrim $ \case
+                         VNaturalLit 0 ->
+                           VHLam NaturalSubtractZero id
+                         x@(VNaturalLit m) ->
+                           VPrim $ \case
+                               VNaturalLit n
+                                 | n >= m    -> VNaturalLit (subtract m n)
+                                 | otherwise -> VNaturalLit 0
+                               y -> VNaturalSubtract x y
+                         x ->
+                           VPrim $ \case
+                             VNaturalLit 0 -> VNaturalLit 0
+                             y | conv env x y -> VNaturalLit 0
+                             y -> VNaturalSubtract x y
     NaturalPlus t u  -> vNaturalPlus (evalE t) (evalE u)
     NaturalTimes t u -> case (evalE t, evalE u) of
                           (VNaturalLit 1, u            ) -> u
@@ -512,19 +553,16 @@
     Record kts       -> VRecord (Dhall.Map.sort (evalE <$> kts))
     RecordLit kts    -> VRecordLit (Dhall.Map.sort (evalE <$> kts))
     Union kts        -> VUnion (Dhall.Map.sort ((evalE <$>) <$> kts))
-    UnionLit k v kts -> VUnionLit k (evalE v) (Dhall.Map.sort ((evalE <$>) <$> kts))
     Combine t u      -> vCombine (evalE t) (evalE u)
     CombineTypes t u -> vCombineTypes (evalE t) (evalE u)
     Prefer t u       -> case (evalE t, evalE u) of
                           (VRecordLit m, u) | null m -> u
                           (t, VRecordLit m) | null m -> t
                           (VRecordLit m, VRecordLit m') ->
-                             VRecordLit (Dhall.Map.sort (Dhall.Map.union m' m))
+                             VRecordLit (Dhall.Map.union m' m)
+                          (t, u) | conv env t u -> t
                           (t, u) -> VPrefer t u
     Merge x y ma     -> case (evalE x, evalE y, evalE <$> ma) of
-                          (VRecordLit m, VUnionLit k v _, _)
-                            | Just f <- Dhall.Map.lookup k m -> f `vApp` v
-                            | otherwise -> error errorMsg
                           (VRecordLit m, VInject _ k mt, _)
                             | Just f  <- Dhall.Map.lookup k m -> maybe f (vApp f) mt
                             | otherwise -> error errorMsg
@@ -539,28 +577,22 @@
                             s = (Data.Sequence.fromList . map entry . Dhall.Map.toList) m
                             in VListLit Nothing s
                           (x, ma) -> VToMap x ma
-    Field t k        -> case evalE t of
-                          VRecordLit m
-                            | Just v <- Dhall.Map.lookup k m -> v
-                            | otherwise -> error errorMsg
-                          VUnion m -> case Dhall.Map.lookup k m of
-                            Just (Just _) -> VPrim $ \ ~u -> VInject m k (Just u)
-                            Just Nothing  -> VInject m k Nothing
-                            _             -> error errorMsg
-                          t -> VField t k
+    Field t k        -> vField (evalE t) k
     Project t (Left ks) ->
                         if null ks then
                           VRecordLit mempty
                         else case evalE t of
                           VRecordLit kvs -> let
                             kvs' = Dhall.Map.restrictKeys kvs (Dhall.Set.toSet ks)
-                            in VRecordLit (Dhall.Map.sort kvs')
+                            in VRecordLit kvs'
                           t -> VProject t (Left (Dhall.Set.sort ks))
     Project t (Right e) ->
                         case evalE e of
                           VRecord kts ->
                             evalE (Project t (Left (Dhall.Set.fromSet (Dhall.Map.keysSet kts))))
                           e' -> VProject (evalE t) (Right e')
+    Assert t         -> VAssert (evalE t)
+    Equivalent t u   -> VEquivalent (evalE t) (evalE u)
     Note _ e         -> evalE e
     ImportAlt t _    -> evalE t
     Embed a          -> VEmbed a
@@ -653,14 +685,15 @@
     (VNaturalFold t _ u v, VNaturalFold t' _ u' v') ->
       convE t t' && convE u u' && convE v v'
 
-    (VNaturalBuild t     , VNaturalBuild t')     -> convE t t'
-    (VNaturalIsZero t    , VNaturalIsZero t')    -> convE t t'
-    (VNaturalEven t      , VNaturalEven t')      -> convE t t'
-    (VNaturalOdd t       , VNaturalOdd t')       -> convE t t'
-    (VNaturalToInteger t , VNaturalToInteger t') -> convE t t'
-    (VNaturalShow t      , VNaturalShow t')      -> convE t t'
-    (VNaturalPlus t u    , VNaturalPlus t' u')   -> convE t t' && convE u u'
-    (VNaturalTimes t u   , VNaturalTimes t' u')  -> convE t t' && convE u u'
+    (VNaturalBuild t      , VNaturalBuild t')       -> convE t t'
+    (VNaturalIsZero t     , VNaturalIsZero t')      -> convE t t'
+    (VNaturalEven t       , VNaturalEven t')        -> convE t t'
+    (VNaturalOdd t        , VNaturalOdd t')         -> convE t t'
+    (VNaturalToInteger t  , VNaturalToInteger t')   -> convE t t'
+    (VNaturalShow t       , VNaturalShow t')        -> convE t t'
+    (VNaturalSubtract x y , VNaturalSubtract x' y') -> convE x x' && convE y y'
+    (VNaturalPlus t u     , VNaturalPlus t' u')     -> convE t t' && convE u u'
+    (VNaturalTimes t u    , VNaturalTimes t' u')    -> convE t t' && convE u u'
 
     (VInteger           , VInteger)            -> True
     (VIntegerLit t      , VIntegerLit t')      -> t == t'
@@ -668,8 +701,9 @@
     (VIntegerToDouble t , VIntegerToDouble t') -> convE t t'
 
     (VDouble       , VDouble)        -> True
-    (VDoubleLit n  , VDoubleLit n')  -> Dhall.Binary.encode (DoubleLit n  :: Expr X Import) ==
-                                        Dhall.Binary.encode (DoubleLit n' :: Expr X Import)
+    (VDoubleLit n  , VDoubleLit n')  ->
+            Serialise.serialise (Dhall.Binary.encode (DoubleLit n  :: Expr Void Import))
+        ==  Serialise.serialise (Dhall.Binary.encode (DoubleLit n' :: Expr Void Import))
     (VDoubleShow t , VDoubleShow t') -> convE t t'
 
     (VText, VText) -> True
@@ -698,8 +732,6 @@
     (VRecord m               , VRecord m'                  ) -> eqMapsBy convE m m'
     (VRecordLit m            , VRecordLit m'               ) -> eqMapsBy convE m m'
     (VUnion m                , VUnion m'                   ) -> eqMapsBy (eqMaybeBy convE) m m'
-    (VUnionLit k v m         , VUnionLit k' v' m'          ) -> k == k' && convE v v' &&
-                                                                  eqMapsBy (eqMaybeBy convE)  m m'
     (VCombine t u            , VCombine t' u'              ) -> convE t t' && convE u u'
     (VCombineTypes t u       , VCombineTypes t' u'         ) -> convE t t' && convE u u'
     (VPrefer  t u            , VPrefer t' u'               ) -> convE t t' && convE u u'
@@ -708,6 +740,8 @@
     (VField t k              , VField t' k'                ) -> convE t t' && k == k'
     (VProject t (Left ks)    , VProject t' (Left ks')      ) -> convE t t' && ks == ks'
     (VProject t (Right e)    , VProject t' (Right e')      ) -> convE t t' && convE e e'
+    (VAssert t               , VAssert t'                  ) -> convE t t'
+    (VEquivalent t u         , VEquivalent t' u'           ) -> convE t t' && convE u u'
     (VInject m k mt          , VInject m' k' mt'           ) -> eqMapsBy (eqMaybeBy convE) m m'
                                                                   && k == k' && eqMaybeBy convE mt mt'
     (VEmbed a                , VEmbed a'                   ) -> a == a'
@@ -777,6 +811,7 @@
                                        NaturalFoldCl{}           -> quote env (t VPrimVar)
                                        ListFoldCl{}              -> quote env (t VPrimVar)
                                        OptionalFoldCl{}          -> quote env (t VPrimVar)
+                                       NaturalSubtractZero       -> App NaturalSubtract (NaturalLit 0)
 
     VPi a (freshCl -> (x, v, b))  -> Pi x (quoteE a) (quoteBind x (inst b v))
     VHPi (fresh -> (x, v)) a b    -> Pi x (quoteE a) (quoteBind x (b v))
@@ -800,6 +835,7 @@
     VNaturalShow t                -> NaturalShow `qApp` t
     VNaturalPlus t u              -> NaturalPlus (quoteE t) (quoteE u)
     VNaturalTimes t u             -> NaturalTimes (quoteE t) (quoteE u)
+    VNaturalSubtract x y          -> NaturalSubtract `qApp` x `qApp` y
 
     VInteger                      -> Integer
     VIntegerLit n                 -> IntegerLit n
@@ -834,7 +870,6 @@
     VRecord m                     -> Record (quoteE <$> m)
     VRecordLit m                  -> RecordLit (quoteE <$> m)
     VUnion m                      -> Union ((quoteE <$>) <$> m)
-    VUnionLit k v m               -> UnionLit k (quoteE v) ((quoteE <$>) <$> m)
     VCombine t u                  -> Combine (quoteE t) (quoteE u)
     VCombineTypes t u             -> CombineTypes (quoteE t) (quoteE u)
     VPrefer t u                   -> Prefer (quoteE t) (quoteE u)
@@ -842,6 +877,8 @@
     VToMap t ma                   -> ToMap (quoteE t) (quoteE <$> ma)
     VField t k                    -> Field (quoteE t) k
     VProject t p                  -> Project (quoteE t) (fmap quoteE p)
+    VAssert t                     -> Assert (quoteE t)
+    VEquivalent t u               -> Equivalent (quoteE t) (quoteE u)
     VInject m k Nothing           -> Field (Union ((quoteE <$>) <$> m)) k
     VInject m k (Just t)          -> Field (Union ((quoteE <$>) <$> m)) k `qApp` t
     VEmbed a                      -> Embed a
@@ -886,19 +923,10 @@
       Lam x t u        -> Lam "_" (go t) (goBind x u)
       Pi x a b         -> Pi "_" (go a) (goBind x b)
       App t u          -> App (go t) (go u)
-
-      Let (b :| bs) u  ->
-        let Binding x a t = b
-
-            nil = (NBind e x, Binding "_" (goEnv e <$> a) (goEnv e t) :| [])
-
-            snoc (e, bs) (Binding x a t) =
-                (NBind e x, cons (Binding "_" (goEnv e <$> a) (goEnv e t)) bs)
-
-            (e', Data.List.NonEmpty.reverse -> bs') = foldl' snoc nil bs
-
-        in Let bs' (goEnv e' u)
-
+      Let (Binding src0 x src1 mA src2 a) b ->
+          Let (Binding src0 "_" src1 (adapt <$> mA) src2 (go a)) (goBind x b)
+        where
+          adapt (src3, _A) = (src3, go _A)
       Annot t u        -> Annot (go t) (go u)
       Bool             -> Bool
       BoolLit b        -> BoolLit b
@@ -916,6 +944,7 @@
       NaturalOdd       -> NaturalOdd
       NaturalToInteger -> NaturalToInteger
       NaturalShow      -> NaturalShow
+      NaturalSubtract  -> NaturalSubtract
       NaturalPlus t u  -> NaturalPlus  (go t) (go u)
       NaturalTimes t u -> NaturalTimes (go t) (go u)
       Integer          -> Integer
@@ -947,7 +976,6 @@
       Record kts       -> Record (go <$> kts)
       RecordLit kts    -> RecordLit (go <$> kts)
       Union kts        -> Union ((go <$>) <$> kts)
-      UnionLit k v kts -> UnionLit k (go v) ((go <$>) <$> kts)
       Combine t u      -> Combine (go t) (go u)
       CombineTypes t u -> CombineTypes  (go t) (go u)
       Prefer t u       -> Prefer (go t) (go u)
@@ -955,6 +983,8 @@
       ToMap x ma       -> ToMap (go x) (go <$> ma)
       Field t k        -> Field (go t) k
       Project t ks     -> Project (go t) (go <$> ks)
+      Assert t         -> Assert (go t)
+      Equivalent t u   -> Equivalent (go t) (go u)
       Note s e         -> Note s (go e)
       ImportAlt t u    -> ImportAlt (go t) (go u)
       Embed a          -> Embed a
diff --git a/src/Dhall/Freeze.hs b/src/Dhall/Freeze.hs
--- a/src/Dhall/Freeze.hs
+++ b/src/Dhall/Freeze.hs
@@ -18,13 +18,10 @@
 import Data.Monoid ((<>))
 import Data.Maybe (fromMaybe)
 import Data.Text
-import Dhall.Binary (StandardVersion(..))
 import Dhall.Core (Expr(..), Import(..), ImportHashed(..), ImportType(..))
-import Dhall.Import (standardVersion)
 import Dhall.Parser (exprAndHeaderFromText, Src)
 import Dhall.Pretty (CharacterSet, annToAnsiStyle, layoutOpts, prettyCharacterSet)
 import Dhall.TypeCheck (X)
-import Lens.Family (set)
 import System.Console.ANSI (hSupportsANSI)
 
 import qualified Control.Exception
@@ -43,10 +40,9 @@
 freezeImport
     :: FilePath
     -- ^ Current working directory
-    -> StandardVersion
     -> Import
     -> IO Import
-freezeImport directory _standardVersion import_ = do
+freezeImport directory import_ = do
     let unprotectedImport =
             import_
                 { importHashed =
@@ -55,10 +51,7 @@
                         }
                 }
 
-    let status =
-            set standardVersion
-                _standardVersion
-                (Dhall.Import.emptyStatus directory)
+    let status = Dhall.Import.emptyStatus directory
 
     let download =
             State.evalStateT (Dhall.Import.loadWith (Embed import_)) status
@@ -80,7 +73,7 @@
     -- make sure the frozen import is present in the semantic cache
     Dhall.Import.writeExpressionToSemanticCache expression
 
-    let expressionHash = Dhall.Import.hashExpression _standardVersion normalizedExpression
+    let expressionHash = Dhall.Import.hashExpression normalizedExpression
 
     let newImportHashed = (importHashed import_) { hash = Just expressionHash }
 
@@ -92,15 +85,14 @@
 freezeRemoteImport
     :: FilePath
     -- ^ Current working directory
-    -> StandardVersion
     -> Import
     -> IO Import
-freezeRemoteImport directory _standardVersion import_ = do
+freezeRemoteImport directory import_ = do
     case importType (importHashed import_) of
-        Remote {} -> freezeImport directory _standardVersion import_
+        Remote {} -> freezeImport directory import_
         _         -> return import_
 
-writeExpr :: Maybe FilePath -> (Text, Expr s Import) -> CharacterSet -> IO ()
+writeExpr :: Maybe FilePath -> (Text, Expr Src Import) -> CharacterSet -> IO ()
 writeExpr inplace (header, expr) characterSet = do
     let doc =  Pretty.pretty header
             <> Dhall.Pretty.prettyCharacterSet characterSet expr
@@ -147,9 +139,8 @@
     -> Scope
     -> Intent
     -> CharacterSet
-    -> StandardVersion
     -> IO ()
-freeze inplace scope intent characterSet _standardVersion = do
+freeze inplace scope intent characterSet = do
     (text, directory) <- case inplace of
         Nothing -> do
             text <- Data.Text.IO.getContents
@@ -168,7 +159,7 @@
                 AllImports        -> freezeImport
                 OnlyRemoteImports -> freezeRemoteImport
 
-    let freezeFunction = freezeScope directory _standardVersion
+    let freezeFunction = freezeScope directory
 
     let cache
             (ImportAlt
diff --git a/src/Dhall/Hash.hs b/src/Dhall/Hash.hs
--- a/src/Dhall/Hash.hs
+++ b/src/Dhall/Hash.hs
@@ -7,10 +7,8 @@
       hash
     ) where
 
-import Dhall.Binary (StandardVersion)
 import Dhall.Parser (exprFromText)
-import Dhall.Import (hashExpressionToCode, standardVersion)
-import Lens.Family (set)
+import Dhall.Import (hashExpressionToCode)
 
 import qualified Control.Monad.Trans.State.Strict as State
 import qualified Control.Exception
@@ -20,16 +18,15 @@
 import qualified Data.Text.IO
 
 -- | Implementation of the @dhall hash@ subcommand
-hash :: StandardVersion -> IO ()
-hash _standardVersion = do
+hash :: IO ()
+hash = do
     inText <- Data.Text.IO.getContents
 
     parsedExpression <- case exprFromText "(stdin)" inText of
         Left  exception        -> Control.Exception.throwIO exception
         Right parsedExpression -> return parsedExpression
 
-    let status =
-            set standardVersion _standardVersion (Dhall.Import.emptyStatus ".")
+    let status = Dhall.Import.emptyStatus "."
 
     resolvedExpression <- State.evalStateT (Dhall.Import.loadWith parsedExpression) status
 
@@ -40,5 +37,4 @@
     let normalizedExpression =
             Dhall.Core.alphaNormalize (Dhall.Core.normalize resolvedExpression)
 
-    Data.Text.IO.putStrLn
-        (hashExpressionToCode _standardVersion normalizedExpression)
+    Data.Text.IO.putStrLn (hashExpressionToCode normalizedExpression)
diff --git a/src/Dhall/Import.hs b/src/Dhall/Import.hs
--- a/src/Dhall/Import.hs
+++ b/src/Dhall/Import.hs
@@ -101,6 +101,7 @@
 module Dhall.Import (
     -- * Import
       load
+    , loadRelativeTo
     , loadWith
     , localToPath
     , hashExpression
@@ -108,6 +109,7 @@
     , writeExpressionToSemanticCache
     , assertNoImports
     , Status
+    , SemanticCacheMode(..)
     , Chained
     , chainedImport
     , chainedFromLocalHere
@@ -119,7 +121,6 @@
     , graph
     , remote
     , toHeaders
-    , standardVersion
     , normalizer
     , startingContext
     , chainImport
@@ -149,6 +150,7 @@
 import Data.List.NonEmpty (NonEmpty(..))
 import Data.Semigroup (Semigroup(..))
 import Data.Text (Text)
+import Data.Void (absurd)
 #if MIN_VERSION_base(4,8,0)
 #else
 import Data.Traversable (traverse)
@@ -158,7 +160,6 @@
 import Dhall.Binary (StandardVersion(..))
 import Dhall.Core
     ( Expr(..)
-    , Binding(..)
     , Chunks(..)
     , Directory(..)
     , File(..)
@@ -168,6 +169,8 @@
     , ImportMode(..)
     , Import(..)
     , URL(..)
+    , bindingExprs
+    , chunkExprs
     )
 #ifdef MIN_VERSION_http_client
 import Network.HTTP.Client (Manager)
@@ -176,7 +179,7 @@
 import Dhall.Import.Types
 
 import Dhall.Parser (Parser(..), ParseError(..), Src(..), SourcedException(..))
-import Dhall.TypeCheck (X(..))
+import Dhall.TypeCheck (X)
 import Lens.Family.State.Strict (zoom)
 
 import qualified Codec.Serialise
@@ -493,7 +496,10 @@
 loadImportWithSemanticCache
   import_@(Chained (Import (ImportHashed (Just semanticHash) _) _)) = do
     Status { .. } <- State.get
-    mCached <- liftIO $ fetchFromSemanticCache semanticHash
+    mCached <-
+        case _semanticCacheMode of
+            UseSemanticCache -> liftIO $ fetchFromSemanticCache semanticHash
+            IgnoreSemanticCache -> pure Nothing
 
     case mCached of
         Just bytesStrict -> do
@@ -523,8 +529,8 @@
                 Just bytes -> liftIO $ writeToSemanticCache semanticHash bytes
                 Nothing -> do
                     let expectedHash = semanticHash
-                    Status { _standardVersion, _stack } <- State.get
-                    let actualHash = hashExpression _standardVersion (Dhall.Core.alphaNormalize importSemantics)
+                    Status { _stack } <- State.get
+                    let actualHash = hashExpression (Dhall.Core.alphaNormalize importSemantics)
                     throwMissingImport (Imported _stack (HashMismatch {..}))
 
             return (ImportSemantics {..})
@@ -541,7 +547,7 @@
 writeExpressionToSemanticCache :: Expr Src X -> IO ()
 writeExpressionToSemanticCache expression = writeToSemanticCache hash bytes
   where
-    bytes = encodeExpression Dhall.Binary.defaultStandardVersion expression
+    bytes = encodeExpression NoVersion expression
     hash = Crypto.Hash.hash bytes
 
 writeToSemanticCache :: Crypto.Hash.Digest SHA256 -> Data.ByteString.ByteString -> IO ()
@@ -608,7 +614,7 @@
                 Left  err -> throwMissingImport (Imported _stack err)
                 Right _ -> return (Dhall.Core.normalizeWith _normalizer resolvedExpr)
 
-            let bytes = encodeExpression _standardVersion betaNormal
+            let bytes = encodeExpression NoVersion betaNormal
             lift $ writeToSemisemanticCache semisemanticHash bytes
 
             return betaNormal
@@ -654,8 +660,7 @@
 -- https://github.com/dhall-lang/dhall-haskell/issues/1098 for further
 -- discussion.
 computeSemisemanticHash :: Expr Src X -> Crypto.Hash.Digest Crypto.Hash.SHA256
-computeSemisemanticHash resolvedExpr =
-    hashExpression Dhall.Binary.defaultStandardVersion resolvedExpr
+computeSemisemanticHash resolvedExpr = hashExpression resolvedExpr
 
 -- Fetch encoded normal form from "semi-semantic cache"
 fetchFromSemisemanticCache :: Crypto.Hash.Digest SHA256 -> IO (Maybe Data.ByteString.ByteString)
@@ -906,9 +911,7 @@
   Lam a b c            -> Lam <$> pure a <*> loadWith b <*> loadWith c
   Pi a b c             -> Pi <$> pure a <*> loadWith b <*> loadWith c
   App a b              -> App <$> loadWith a <*> loadWith b
-  Let as b             -> Let <$> traverse f as <*> loadWith b
-    where
-      f (Binding c d e) = Binding c <$> traverse loadWith d <*> loadWith e
+  Let a b              -> Let <$> bindingExprs loadWith a <*> loadWith b
   Annot a b            -> Annot <$> loadWith a <*> loadWith b
   Bool                 -> pure Bool
   BoolLit a            -> pure (BoolLit a)
@@ -926,6 +929,7 @@
   NaturalOdd           -> pure NaturalOdd
   NaturalToInteger     -> pure NaturalToInteger
   NaturalShow          -> pure NaturalShow
+  NaturalSubtract      -> pure NaturalSubtract
   NaturalPlus a b      -> NaturalPlus <$> loadWith a <*> loadWith b
   NaturalTimes a b     -> NaturalTimes <$> loadWith a <*> loadWith b
   Integer              -> pure Integer
@@ -936,7 +940,7 @@
   DoubleLit a          -> pure (DoubleLit a)
   DoubleShow           -> pure DoubleShow
   Text                 -> pure Text
-  TextLit (Chunks a b) -> fmap TextLit (Chunks <$> mapM (mapM loadWith) a <*> pure b)
+  TextLit chunks       -> TextLit <$> chunkExprs loadWith chunks
   TextAppend a b       -> TextAppend <$> loadWith a <*> loadWith b
   TextShow             -> pure TextShow
   List                 -> pure List
@@ -957,7 +961,6 @@
   Record a             -> Record <$> mapM loadWith a
   RecordLit a          -> RecordLit <$> mapM loadWith a
   Union a              -> Union <$> mapM (mapM loadWith) a
-  UnionLit a b c       -> UnionLit <$> pure a <*> loadWith b <*> mapM (mapM loadWith) c
   Combine a b          -> Combine <$> loadWith a <*> loadWith b
   CombineTypes a b     -> CombineTypes <$> loadWith a <*> loadWith b
   Prefer a b           -> Prefer <$> loadWith a <*> loadWith b
@@ -965,6 +968,8 @@
   ToMap a b            -> ToMap <$> loadWith a <*> mapM loadWith b
   Field a b            -> Field <$> loadWith a <*> pure b
   Project a b          -> Project <$> loadWith a <*> mapM loadWith b
+  Assert a             -> Assert <$> loadWith a
+  Equivalent a b       -> Equivalent <$> loadWith a <*> loadWith b
   Note a b             -> do
       let handler e = throwM (SourcedException a (e :: MissingImports))
 
@@ -972,12 +977,20 @@
 
 -- | Resolve all imports within an expression
 load :: Expr Src Import -> IO (Expr Src X)
-load expression = State.evalStateT (loadWith expression) (emptyStatus ".")
+load = loadRelativeTo "." UseSemanticCache
 
+-- | Resolve all imports within an expression, importing relative to the given
+-- directory.
+loadRelativeTo :: FilePath -> SemanticCacheMode -> Expr Src Import -> IO (Expr Src X)
+loadRelativeTo rootDirectory semanticCacheMode expression =
+    State.evalStateT
+        (loadWith expression)
+        (emptyStatus rootDirectory) { _semanticCacheMode = semanticCacheMode }
+
 encodeExpression
     :: forall s
     .  StandardVersion
-    -- ^ `Nothing` means to encode without the version tag
+    -- ^ `NoVersion` means to encode without the version tag
     -> Expr s X
     -> Data.ByteString.ByteString
 encodeExpression _standardVersion expression = bytesStrict
@@ -1001,10 +1014,9 @@
     bytesStrict = Data.ByteString.Lazy.toStrict bytesLazy
 
 -- | Hash a fully resolved expression
-hashExpression
-    :: StandardVersion -> Expr s X -> (Crypto.Hash.Digest SHA256)
-hashExpression _standardVersion expression =
-    Crypto.Hash.hash (encodeExpression _standardVersion expression)
+hashExpression :: Expr s X -> (Crypto.Hash.Digest SHA256)
+hashExpression expression =
+    Crypto.Hash.hash (encodeExpression NoVersion expression)
 
 {-| Convenience utility to hash a fully resolved expression and return the
     base-16 encoded hash with the @sha256:@ prefix
@@ -1012,9 +1024,9 @@
     In other words, the output of this function can be pasted into Dhall
     source code to add an integrity check to an import
 -}
-hashExpressionToCode :: StandardVersion -> Expr s X -> Text
-hashExpressionToCode _standardVersion expr =
-    "sha256:" <> Text.pack (show (hashExpression _standardVersion expr))
+hashExpressionToCode :: Expr s X -> Text
+hashExpressionToCode expr =
+    "sha256:" <> Text.pack (show (hashExpression expr))
 
 -- | A call to `assertNoImports` failed because there was at least one import
 data ImportResolutionDisabled = ImportResolutionDisabled deriving (Exception)
diff --git a/src/Dhall/Import/HTTP.hs b/src/Dhall/Import/HTTP.hs
--- a/src/Dhall/Import/HTTP.hs
+++ b/src/Dhall/Import/HTTP.hs
@@ -51,60 +51,129 @@
 import qualified Network.HTTP.Client.TLS                 as HTTP
 import qualified Network.HTTP.Types
 
-mkPrettyHttpException :: HttpException -> PrettyHttpException
-mkPrettyHttpException ex =
-    PrettyHttpException (renderPrettyHttpException ex) (toDyn ex)
+mkPrettyHttpException :: String -> HttpException -> PrettyHttpException
+mkPrettyHttpException url ex =
+    PrettyHttpException (renderPrettyHttpException url ex) (toDyn ex)
 
-renderPrettyHttpException :: HttpException -> String
+renderPrettyHttpException :: String -> HttpException -> String
 #if MIN_VERSION_http_client(0,5,0)
-renderPrettyHttpException (InvalidUrlException _ r) =
-  "\n"
+renderPrettyHttpException _ (InvalidUrlException _ r) =
+      "\n"
   <>  "\ESC[1;31mError\ESC[0m: Invalid URL\n"
   <>  "\n"
-  <>  "↳ " <> show r
-renderPrettyHttpException (HttpExceptionRequest _ e) =
+  <>  "URL: " <> show r <> "\n"
+renderPrettyHttpException url (HttpExceptionRequest _ e) =
   case e of
     ConnectionFailure _ ->
-      "\n"
+          "\n"
       <>  "\ESC[1;31mError\ESC[0m: Remote host not found\n"
+      <>  "\n"
+      <>  "URL: " <> url <> "\n"
     InvalidDestinationHost host ->
-      "\n"
-      <>  "\ESC[1;31mError\ESC[0m: Invalid remote host name\n"
+          "\n"
+      <>  "\ESC[1;31mError\ESC[0m: Invalid remote host name:\n"
       <>  "\n"
-      <>  "↳ " <> show host
+      <>  "Host: " <> show host <> "\n"
     ResponseTimeout ->
-      "\n"
-      <>  "\ESC[1;31mError\ESC[0m: The remote host took too long to respond"
-    StatusCodeException response _
-        | statusCode == 404 ->
-            "\n"
-            <>  "\ESC[1;31mError\ESC[0m: Remote file not found"
-        | otherwise ->
-            "\n"
-            <>  "\ESC[1;31mError\ESC[0m: Unexpected HTTP status code:\n"
-            <>  "\n"
-            <>  "↳ " <> show statusCode
+          "\n"
+      <>  "\ESC[1;31mError\ESC[0m: The remote host took too long to respond\n"
+      <>  "\n"
+      <>  "URL: " <> url <> "\n"
+    StatusCodeException response body -> prefix <> suffix
       where
+        prefix
+            | statusCode == 401 =
+                    "\n"
+                <>  "\ESC[1;31mError\ESC[0m: Access unauthorized\n"
+            | statusCode == 403 =
+                    "\n"
+                <>  "\ESC[1;31mError\ESC[0m: Access forbidden\n"
+            | statusCode == 404 =
+                    "\n"
+                <>  "\ESC[1;31mError\ESC[0m: Remote file not found\n"
+            | statusCode == 500 =
+                    "\n"
+                <>  "\ESC[1;31mError\ESC[0m: Server-side failure\n"
+            | statusCode == 502 =
+                    "\n"
+                <>  "\ESC[1;31mError\ESC[0m: Upstream failure\n"
+            | statusCode == 503 =
+                    "\n"
+                <>  "\ESC[1;31mError\ESC[0m: Server temporarily unavailable\n"
+            | statusCode == 504 =
+                    "\n"
+                <>  "\ESC[1;31mError\ESC[0m: Upstream timeout\n"
+            | otherwise =
+                    "\n"
+                <>  "\ESC[1;31mError\ESC[0m: HTTP request failure\n"
+
+        suffix =
+                "\n"
+            <>  "HTTP status code: " <> show statusCode <> "\n"
+            <>  "\n"
+            <>  "URL: " <> url <> "\n"
+            <>  message
+
         statusCode =
             Network.HTTP.Types.statusCode
                 (HTTP.responseStatus response)
-    e' -> "\n" <> show e'
+
+        message =
+            case Data.Text.Encoding.decodeUtf8' body of
+                Left _ ->
+                        "\n"
+                    <>  "Message (non-UTF8 bytes):\n"
+                    <>  "\n"
+                    <>  truncatedBodyString <> "\n"
+                  where
+                    bodyString = show body
+
+                    dots = "…"
+
+                    truncatedLength = 80 - length dots
+
+                    truncatedBodyString
+                        | truncatedLength < length bodyString =
+                            take truncatedLength bodyString <> dots
+                        | otherwise =
+                            bodyString
+                Right "" ->
+                    ""
+                Right bodyText ->
+                        "\n"
+                    <>  "Message:\n"
+                    <>  "\n"
+                    <>  Text.unpack prefixedText
+                  where
+                    prefixedLines =
+                        zipWith combine prefixes (Text.lines bodyText)
+                      where
+                        prefixes =
+                            map (Text.pack . show) [(1 ::Int)..7] ++ [ "…" ]
+
+                        combine n line = n <> "│ " <> line
+
+                    prefixedText = Text.unlines prefixedLines
+
+    e' -> "\n" <> show e' <> "\n"
 #else
-renderPrettyHttpException e = case e of
+renderPrettyHttpException url e = case e of
     FailedConnectionException2 _ _ _ e' ->
             "\n"
-        <>  "\ESC[1;31mError\ESC[0m: Wrong host\n"
+        <>  "\ESC[1;31mError\ESC[0m: Wrong host:\n"
         <>  "\n"
-        <>  "↳ " <> show e'
+        <>  "Host: " <> show e' <> "\n"
     InvalidDestinationHost host ->
             "\n"
-        <>  "\ESC[1;31mError\ESC[0m: Invalid host name\n"
+        <>  "\ESC[1;31mError\ESC[0m: Invalid host name:\n"
         <>  "\n"
-        <>  "↳ " <> show host
+        <>  "Host: " <> show host <> "\n"
     ResponseTimeout ->
             "\ESC[1;31mError\ESC[0m: The host took too long to respond\n"
+        <>  "\n"
+        <>  "URL: " <> url <> "\n"
     e' ->   "\n"
-        <> show e'
+        <>  show e' <> "\n"
 #endif
 
 newManager :: IO Manager
@@ -262,7 +331,7 @@
 
     let handler e = do
             let _ = e :: HttpException
-            Control.Exception.throwIO (mkPrettyHttpException e)
+            Control.Exception.throwIO (mkPrettyHttpException childURLString e)
 
     response <- liftIO (Control.Exception.handle handler io)
 
diff --git a/src/Dhall/Import/Types.hs b/src/Dhall/Import/Types.hs
--- a/src/Dhall/Import/Types.hs
+++ b/src/Dhall/Import/Types.hs
@@ -11,7 +11,6 @@
 import Data.Map (Map)
 import Data.Semigroup ((<>))
 import Data.Text.Prettyprint.Doc (Pretty(..))
-import Dhall.Binary (StandardVersion(..))
 import Dhall.Context (Context)
 import Dhall.Core
   ( Directory (..)
@@ -30,7 +29,6 @@
 import Lens.Family (LensLike')
 import System.FilePath (isRelative, splitDirectories)
 
-import qualified Dhall.Binary
 import qualified Dhall.Context
 import qualified Data.Map      as Map
 import qualified Data.Text
@@ -54,6 +52,8 @@
 -- | `parent` imports (i.e. depends on) `child`
 data Depends = Depends { parent :: Chained, child :: Chained }
 
+data SemanticCacheMode = IgnoreSemanticCache | UseSemanticCache
+
 -- | State threaded throughout the import process
 data Status = Status
     { _stack :: NonEmpty Chained
@@ -71,11 +71,11 @@
     , _remote :: URL -> StateT Status IO Data.Text.Text
     -- ^ The remote resolver, fetches the content at the given URL.
 
-    , _standardVersion :: StandardVersion
-
     , _normalizer :: Maybe (ReifiedNormalizer X)
 
     , _startingContext :: Context (Expr Src X)
+
+    , _semanticCacheMode :: SemanticCacheMode
     }
 
 -- | Initial `Status`, parameterised over the remote resolver, importing
@@ -89,14 +89,12 @@
 
     _cache = Map.empty
 
-    _manager = Nothing
-
-    _standardVersion = Dhall.Binary.defaultStandardVersion
-
     _normalizer = Nothing
 
     _startingContext = Dhall.Context.empty
 
+    _semanticCacheMode = UseSemanticCache
+
     prefix = if isRelative rootDirectory
       then Here
       else Absolute
@@ -125,10 +123,6 @@
 
 remote :: Functor f => LensLike' f Status (URL -> StateT Status IO Data.Text.Text)
 remote k s = fmap (\x -> s { _remote = x }) (k (_remote s))
-
-standardVersion :: Functor f => LensLike' f Status StandardVersion
-standardVersion k s =
-    fmap (\x -> s { _standardVersion = x }) (k (_standardVersion s))
 
 normalizer :: Functor f => LensLike' f Status (Maybe (ReifiedNormalizer X))
 normalizer k s = fmap (\x -> s {_normalizer = x}) (k (_normalizer s))
diff --git a/src/Dhall/Lint.hs b/src/Dhall/Lint.hs
--- a/src/Dhall/Lint.hs
+++ b/src/Dhall/Lint.hs
@@ -3,49 +3,49 @@
 module Dhall.Lint
     ( -- * Lint
       lint
+    , removeUnusedBindings
     ) where
 
-import Data.List.NonEmpty (NonEmpty(..))
-import Data.Semigroup ((<>))
 import Dhall.Core (Binding(..), Expr(..), Import, Var(..), subExpressions)
 
 import qualified Dhall.Core
 import qualified Dhall.Optics
+import qualified Lens.Family
 
 {-| Automatically improve a Dhall expression
 
     Currently this:
 
-    * removes unused @let@ bindings with 'removeLetInLet'.
-    * consolidates nested @let@ bindings to use a multiple-@let@ binding with 'removeUnusedBindings'.
+    * removes unused @let@ bindings with 'removeUnusedBindings'.
+    * consolidates nested @let@ bindings to use a multiple-@let@ binding with 'removeLetInLet'
 -}
 lint :: Expr s Import -> Expr t Import
-lint = postproc . linting . preproc
-  where
-    -- pre-processing: remove Note constructors and unfold Let blocks
-    preproc = Dhall.Optics.rewriteOf subExpressions unfoldNestedLets . Dhall.Core.denote
-    -- main linting step: remove unused let bindings and update optional syntax
-    linting = Dhall.Optics.rewriteOf subExpressions removeUnusedBindings
-    -- post-processing: fold nested Lets into Let blocks
-    postproc = Dhall.Optics.rewriteOf subExpressions removeLetInLet
-
--- Merge nested Let blocks. Only finds immediately nested blocks -- use
--- Dhall.Core.denote to make sure there aren't any Note constructors in the way!
-removeLetInLet :: Eq a => Expr s a -> Maybe (Expr s a)
-removeLetInLet (Let a (Let b c)) = Just (Let (a <> b) c)
-removeLetInLet _ = Nothing
+lint = Dhall.Optics.rewriteOf subExpressions removeUnusedBindings . removeLetInLet
 
--- Remove unused Let bindings. Only considers Let blocks binding a single
--- variable -- unfold Let blocks first to make sure we don't miss any rewrite
--- opportunities!
+-- Remove unused Let bindings.
 removeUnusedBindings :: Eq a => Expr s a -> Maybe (Expr s a)
-removeUnusedBindings (Let (Binding a _ _ :| []) d)
+-- Don't remove assertions!
+removeUnusedBindings (Let (Binding _ _ _ _ _ e) _)
+    | isOrContainsAssert e = Nothing
+removeUnusedBindings (Let (Binding _ a _ _ _ _) d)
     | not (V a 0 `Dhall.Core.freeIn` d) =
         Just (Dhall.Core.shift (-1) (V a 0) d)
 removeUnusedBindings _ = Nothing
 
--- Unfold Let blocks into nested Let bindings binding a single variable each.
--- Pre-processing step before applying the removeUnusedBindings rule.
-unfoldNestedLets :: Expr s a -> Maybe (Expr s a)
-unfoldNestedLets (Let (b :| (l : ls)) d) = Just (Let (b :| []) (Let (l :| ls) d))
-unfoldNestedLets _ = Nothing
+isOrContainsAssert :: Expr s a -> Bool
+isOrContainsAssert (Assert _) = True
+isOrContainsAssert e = Lens.Family.anyOf subExpressions isOrContainsAssert e
+
+-- The difference between
+--
+-- > let x = 1 let y = 2 in x + y
+--
+-- and
+--
+-- > let x = 1 in let y = 2 in x + y
+--
+-- is that in the second expression, the inner 'Let' is wrapped by a 'Note'.
+--
+-- Denoting removes that distinction.
+removeLetInLet :: Expr s a -> Expr t a
+removeLetInLet = Dhall.Core.denote
diff --git a/src/Dhall/Main.hs b/src/Dhall/Main.hs
--- a/src/Dhall/Main.hs
+++ b/src/Dhall/Main.hs
@@ -3,6 +3,7 @@
 -}
 
 {-# LANGUAGE DeriveAnyClass    #-}
+{-# LANGUAGE LambdaCase        #-}
 {-# LANGUAGE NamedFieldPuns    #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards   #-}
@@ -20,22 +21,20 @@
     ) where
 
 import Control.Applicative (optional, (<|>))
-import Control.Exception (SomeException)
+import Control.Exception (Handler(..), SomeException)
 import Data.List.NonEmpty (NonEmpty(..))
 import Data.Monoid ((<>))
 import Data.Text (Text)
 import Data.Text.Prettyprint.Doc (Doc, Pretty)
 import Data.Version (showVersion)
-import Dhall.Binary (StandardVersion)
 import Dhall.Core (Expr(Annot), Import, pretty)
 import Dhall.Freeze (Intent(..), Scope(..))
-import Dhall.Import (Imported(..), Depends(..))
+import Dhall.Import (Imported(..), Depends(..), SemanticCacheMode(..))
 import Dhall.Parser (Src)
 import Dhall.Pretty (Ann, CharacterSet(..), annToAnsiStyle, layoutOpts)
 import Dhall.TypeCheck (DetailedTypeError(..), TypeError, X)
-import Lens.Family (set)
 import Options.Applicative (Parser, ParserInfo)
-import System.Exit (exitFailure)
+import System.Exit (ExitCode, exitFailure)
 import System.IO (Handle)
 import Text.Dot ((.->.))
 
@@ -71,6 +70,7 @@
 import qualified Options.Applicative
 import qualified Paths_dhall as Meta
 import qualified System.Console.ANSI
+import qualified System.Exit                               as Exit
 import qualified System.IO
 import qualified System.FilePath
 import qualified Text.Dot
@@ -82,12 +82,16 @@
     , explain         :: Bool
     , plain           :: Bool
     , ascii           :: Bool
-    , standardVersion :: StandardVersion
     }
 
 -- | The subcommands for the @dhall@ executable
 data Mode
-    = Default { file :: Maybe FilePath, annotate :: Bool, alpha :: Bool }
+    = Default
+          { file :: Maybe FilePath
+          , annotate :: Bool
+          , alpha :: Bool
+          , semanticCacheMode :: SemanticCacheMode
+          }
     | Version
     | Resolve { file :: Maybe FilePath, resolveMode :: Maybe ResolveMode }
     | Type { file :: Maybe FilePath }
@@ -116,7 +120,6 @@
     <*> switch "explain" "Explain error messages in more detail"
     <*> switch "plain" "Disable syntax highlighting"
     <*> switch "ascii" "Format code using only ASCII syntax"
-    <*> Dhall.Binary.parseStandardVersion
   where
     switch name description =
         Options.Applicative.switch
@@ -169,11 +172,11 @@
             (pure Hash)
     <|> subcommand
             "lint"
-            "Improve Dhall code"
+            "Improve Dhall code by using newer language features and removing dead code"
             (Lint <$> optional parseInplace)
     <|> subcommand
             "format"
-            "Formatter for the Dhall language"
+            "Standard code formatter for the Dhall language"
             (Format <$> parseFormatMode)
     <|> subcommand
             "freeze"
@@ -191,7 +194,7 @@
             "text"
             "Render a Dhall expression that evaluates to a Text literal"
             (Text <$> optional parseFile)
-    <|> (Default <$> optional parseFile <*> parseAnnotate <*> parseAlpha)
+    <|> (Default <$> optional parseFile <*> parseAnnotate <*> parseAlpha <*> parseSemanticCacheMode)
   where
     argument =
             fmap Data.Text.pack
@@ -217,6 +220,15 @@
             <>  Options.Applicative.help "Add a type annotation to the output"
             )
 
+    parseSemanticCacheMode =
+        Options.Applicative.flag
+            UseSemanticCache
+            IgnoreSemanticCache
+            (   Options.Applicative.long "no-cache"
+            <>  Options.Applicative.help
+                  "Handle protected imports as if the cache was empty"
+            )
+
     parseResolveMode =
           Options.Applicative.flag' (Just Dot)
               (   Options.Applicative.long "dot"
@@ -277,7 +289,6 @@
 getExpression maybeFile = do
     inText <- do
         case maybeFile of
-            Just "-"  -> Data.Text.IO.getContents
             Just file -> Data.Text.IO.readFile file
             Nothing   -> Data.Text.IO.getContents
 
@@ -301,21 +312,29 @@
 
     GHC.IO.Encoding.setLocaleEncoding System.IO.utf8
 
-    let toStatus maybeFile =
-            set Dhall.Import.standardVersion standardVersion
-                (Dhall.Import.emptyStatus file)
-          where
-            file = case maybeFile of
-                Just "-" -> "."
-                Just f   -> System.FilePath.takeDirectory f
-                Nothing  -> "."
+    let rootDirectory = \case
+            Just f   -> System.FilePath.takeDirectory f
+            Nothing  -> "."
 
-    let handle =
-                Control.Exception.handle handler2
-            .   Control.Exception.handle handler1
-            .   Control.Exception.handle handler0
+    let toStatus = Dhall.Import.emptyStatus . rootDirectory
+
+    let handle io =
+            Control.Exception.catches io
+                [ Handler handleTypeError
+                , Handler handleImported
+                , Handler handleExitCode
+                ]
           where
-            handler0 e = do
+            handleAll e = do
+                let string = show (e :: SomeException)
+
+                if not (null string)
+                    then System.IO.hPutStrLn System.IO.stderr string
+                    else return ()
+
+                System.Exit.exitFailure
+
+            handleTypeError e = Control.Exception.handle handleAll $ do
                 let _ = e :: TypeError Src X
                 System.IO.hPutStrLn System.IO.stderr ""
                 if explain
@@ -324,7 +343,7 @@
                         Data.Text.IO.hPutStrLn System.IO.stderr "\ESC[2mUse \"dhall --explain\" for detailed errors\ESC[0m"
                         Control.Exception.throwIO e
 
-            handler1 (Imported ps e) = do
+            handleImported (Imported ps e) = Control.Exception.handle handleAll $ do
                 let _ = e :: TypeError Src X
                 System.IO.hPutStrLn System.IO.stderr ""
                 if explain
@@ -333,14 +352,8 @@
                         Data.Text.IO.hPutStrLn System.IO.stderr "\ESC[2mUse \"dhall --explain\" for detailed errors\ESC[0m"
                         Control.Exception.throwIO (Imported ps e)
 
-            handler2 e = do
-                let string = show (e :: SomeException)
-
-                if not (null string)
-                    then System.IO.hPutStrLn System.IO.stderr string
-                    else return ()
-
-                System.Exit.exitFailure
+            handleExitCode e = do
+                Control.Exception.throwIO (e :: ExitCode)
 
     let renderDoc :: Handle -> Doc Ann -> IO ()
         renderDoc h doc = do
@@ -355,7 +368,7 @@
             Pretty.renderIO h ansiStream
             Data.Text.IO.hPutStrLn h ""
 
-    let render :: Pretty a => Handle -> Expr s a -> IO ()
+    let render :: Pretty a => Handle -> Expr Src a -> IO ()
         render h expression = do
             let doc = Dhall.Pretty.prettyCharacterSet characterSet expression
 
@@ -368,7 +381,8 @@
         Default {..} -> do
             expression <- getExpression file
 
-            resolvedExpression <- State.evalStateT (Dhall.Import.loadWith expression) (toStatus file)
+            resolvedExpression <-
+                Dhall.Import.loadRelativeTo (rootDirectory file) semanticCacheMode expression
 
             inferredType <- Dhall.Core.throws (Dhall.TypeCheck.typeOf resolvedExpression)
 
@@ -439,8 +453,9 @@
         Resolve { resolveMode = Nothing, ..} -> do
             expression <- getExpression file
 
-            (resolvedExpression, _) <-
-                State.runStateT (Dhall.Import.loadWith expression) (toStatus file)
+            resolvedExpression <-
+                Dhall.Import.loadRelativeTo (rootDirectory file) UseSemanticCache expression
+
             render System.IO.stdout resolvedExpression
 
         Normalize {..} -> do
@@ -462,14 +477,15 @@
         Type {..} -> do
             expression <- getExpression file
 
-            resolvedExpression <- Dhall.Import.assertNoImports expression
+            resolvedExpression <-
+                Dhall.Import.loadRelativeTo (rootDirectory file) UseSemanticCache expression
 
             inferredType <- Dhall.Core.throws (Dhall.TypeCheck.typeOf resolvedExpression)
 
             render System.IO.stdout (Dhall.Core.normalize inferredType)
 
         Repl -> do
-            Dhall.Repl.repl characterSet explain standardVersion
+            Dhall.Repl.repl characterSet explain
 
         Diff {..} -> do
             expression1 <- Dhall.inputExpr expr1
@@ -478,8 +494,12 @@
 
             let diff = Dhall.Diff.diffNormalized expression1 expression2
 
-            renderDoc System.IO.stdout diff
+            renderDoc System.IO.stdout (Dhall.Diff.doc diff)
 
+            if Dhall.Diff.same diff
+                then return ()
+                else Exit.exitFailure
+
         Format {..} -> do
             Dhall.Format.format (Dhall.Format.Format {..})
 
@@ -488,10 +508,10 @@
 
             let intent = if cache then Cache else Secure
 
-            Dhall.Freeze.freeze inplace scope intent characterSet standardVersion
+            Dhall.Freeze.freeze inplace scope intent characterSet
 
         Hash -> do
-            Dhall.Hash.hash standardVersion
+            Dhall.Hash.hash
 
         Lint {..} -> do
             case inplace of
@@ -570,7 +590,8 @@
         Text {..} -> do
             expression <- getExpression file
 
-            resolvedExpression <- State.evalStateT (Dhall.Import.loadWith expression) (toStatus file)
+            resolvedExpression <-
+                Dhall.Import.loadRelativeTo (rootDirectory file) UseSemanticCache expression
 
             _ <- Dhall.Core.throws (Dhall.TypeCheck.typeOf (Annot resolvedExpression Dhall.Core.Text))
 
diff --git a/src/Dhall/Parser.hs b/src/Dhall/Parser.hs
--- a/src/Dhall/Parser.hs
+++ b/src/Dhall/Parser.hs
@@ -26,6 +26,7 @@
 import Dhall.Src (Src(..))
 import Prelude hiding (const, pi)
 
+import qualified Data.Char
 import qualified Data.Text
 import qualified Text.Megaparsec
 
@@ -43,11 +44,11 @@
 exprA = completeExpression
 
 -- | A parsing error
-data ParseError = ParseError
+data ParseError = ParseError {
 #if MIN_VERSION_megaparsec(7, 0, 0)
-    { unwrap :: Text.Megaparsec.ParseErrorBundle Text Void
+      unwrap :: Text.Megaparsec.ParseErrorBundle Text Void
 #else
-    { unwrap :: Text.Megaparsec.ParseError Char Void
+      unwrap :: Text.Megaparsec.ParseError Char Void
 #endif
     , input  :: Text
     }
@@ -89,7 +90,7 @@
     -> Either ParseError (Text, Expr Src Import)
 exprAndHeaderFromText delta text = case result of
     Left errInfo   -> Left (ParseError { unwrap = errInfo, input = text })
-    Right (txt, r) -> Right (Data.Text.dropWhileEnd (/= '\n') txt, r)
+    Right (txt, r) -> Right (stripHeader txt, r)
   where
     parser = do
         (bytes, _) <- Text.Megaparsec.match whitespace
@@ -98,3 +99,5 @@
         return (bytes, r)
 
     result = Text.Megaparsec.parse (unParser parser) delta text
+
+    stripHeader = Data.Text.dropWhile Data.Char.isSpace . Data.Text.dropWhileEnd (/= '\n')
diff --git a/src/Dhall/Parser/Expression.hs b/src/Dhall/Parser/Expression.hs
--- a/src/Dhall/Parser/Expression.hs
+++ b/src/Dhall/Parser/Expression.hs
@@ -67,6 +67,13 @@
 #endif
 {-# INLINE setOffset #-}
 
+src :: Parser a -> Parser Src
+src parser = do
+    before      <- getSourcePos
+    (tokens, _) <- Text.Megaparsec.match parser
+    after       <- getSourcePos
+    return (Src before after tokens)
+
 noted :: Parser (Expr Src a) -> Parser (Expr Src a)
 noted parser = do
     before      <- getSourcePos
@@ -107,6 +114,7 @@
                 , alternative2
                 , alternative3
                 , alternative4
+                , alternative5
                 ]
             ) <?> "expression"
       where
@@ -132,26 +140,54 @@
 
         alternative2 = do
             let binding = do
-                    _let
+                    _letOnly
 
-                    c <- label
+                    src0 <- src nonemptyWhitespace
+
+                    c <- labelOnly
+
+                    src1 <- src whitespace
+
                     d <- optional (do
-                        _colon
-                        expression )
+                        _colonOnly
 
-                    _equal
+                        src2 <- src nonemptyWhitespace
 
-                    e <- expression
+                        e <- expression
+                        return (Just src2, e) )
 
-                    return (Binding c d e)
+                    _equalOnly
 
+                    src3 <- src whitespace
+
+                    f <- expression
+
+                    return (Binding (Just src0) c (Just src1) d (Just src3) f)
+
             as <- Data.List.NonEmpty.some1 binding
 
             _in
 
             b <- expression
 
-            return (Let as b)
+            -- 'Note's in let-in-let:
+            --
+            -- Subsequent @let@s that are not separated by an @in@ only get a
+            -- single surrounding 'Note'. For example:
+            --
+            -- let x = a
+            -- let y = b
+            -- in  let z = c
+            --     in x
+            --
+            -- is parsed as
+            --
+            -- (Note …
+            --   (Let x …
+            --     (Let y …
+            --       (Note …
+            --         (Let z …
+            return (Dhall.Core.wrapInLets as b)
 
         alternative3 = do
             _forall
@@ -165,6 +201,12 @@
             return (Pi a b c)
 
         alternative4 = do
+            _assert
+            _colon
+            a <- expression
+            return (Assert a)
+
+        alternative5 = do
             a <- operatorExpression
 
             let alternative4A = do
@@ -217,7 +259,9 @@
             <|> NaturalTimes <$ _times
             <|> BoolEQ       <$ _doubleEqual
 
-    precedence3Operator = BoolNE <$ _notEqual
+    precedence3Operator
+            =   BoolNE     <$ _notEqual
+            <|> Equivalent <$ _equivalent
 
     precedence0Expression =
             makeOperatorExpression precedence1Expression precedence0Operator
@@ -312,11 +356,7 @@
                 _closeBrace
                 return a ) <?> "record type or literal"
 
-            alternative05 = (do
-                _openAngle
-                a <- unionTypeOrLiteral
-                _closeAngle
-                return a ) <?> "union type or literal"
+            alternative05 = unionType
 
             alternative06 = listLiteral
 
@@ -360,7 +400,7 @@
                             , NaturalIsZero    <$ _NaturalIsZero
                             , NaturalEven      <$ _NaturalEven
                             , NaturalOdd       <$ _NaturalOdd
-                            , NaturalToInteger <$ _NaturalToInteger
+                            , NaturalSubtract  <$ _NaturalSubtract
                             , NaturalToInteger <$ _NaturalToInteger
                             , NaturalShow      <$ _NaturalShow
                             , Natural          <$ _Natural
@@ -630,41 +670,21 @@
 
             nonEmptyRecordType <|> nonEmptyRecordLiteral
 
-    unionTypeOrLiteral =
-                nonEmptyUnionTypeOrLiteral
-            <|> return (Union mempty)
-
-    nonEmptyUnionTypeOrLiteral = do
-            (f, kvs) <- loop
-            m <- toMap kvs
-            return (f m)
-          where
-            loop = do
-                a <- anyLabel
-
-                let alternative0 = do
-                        _equal
-                        b <- expression
-                        kvs <- Text.Megaparsec.many (do
-                            _bar
-                            c <- anyLabel
-                            d <- optional (do _colon; expression)
-                            return (c, d) )
-                        return (UnionLit a b, kvs)
+    unionType = (do
+            _openAngle
 
-                let alternative1 = do
-                        b <- optional (do _colon; expression)
+            let unionTypeEntry = do
+                    a <- anyLabel
+                    b <- optional (do _colon; expression)
+                    return (a, b)
 
-                        let alternative2 = do
-                                _bar
-                                (f, kvs) <- loop
-                                return (f, (a, b):kvs)
+            kvs <- Text.Megaparsec.sepBy unionTypeEntry _bar
 
-                        let alternative3 = return (Union, [(a, b)])
+            m <- toMap kvs
 
-                        alternative2 <|> alternative3
+            _closeAngle
 
-                alternative0 <|> alternative1
+            return (Union m) ) <?> "union type"
 
     listLiteral = (do
             _openBracket
diff --git a/src/Dhall/Parser/Token.hs b/src/Dhall/Parser/Token.hs
--- a/src/Dhall/Parser/Token.hs
+++ b/src/Dhall/Parser/Token.hs
@@ -5,10 +5,12 @@
 module Dhall.Parser.Token (
     validCodepoint,
     whitespace,
+    nonemptyWhitespace,
     bashEnvironmentVariable,
     posixEnvironmentVariable,
     ComponentType(..),
     file_,
+    labelOnly,
     label,
     anyLabel,
     labels,
@@ -24,12 +26,14 @@
     _if,
     _then,
     _else,
+    _letOnly,
     _let,
     _in,
     _as,
     _using,
     _merge,
     _toMap,
+    _assert,
     _Some,
     _None,
     _NaturalFold,
@@ -39,6 +43,7 @@
     _NaturalOdd,
     _NaturalToInteger,
     _NaturalShow,
+    _NaturalSubtract,
     _IntegerShow,
     _IntegerToDouble,
     _DoubleShow,
@@ -65,6 +70,7 @@
     _Kind,
     _Sort,
     _Location,
+    _equalOnly,
     _equal,
     _or,
     _plus,
@@ -85,8 +91,10 @@
     _comma,
     _openParens,
     _closeParens,
+    _colonOnly,
     _colon,
     _at,
+    _equivalent,
     _missing,
     _importAlt,
     _combine,
@@ -319,6 +327,9 @@
         noDuplicates (x : xs)
 
 
+labelOnly :: Parser Text
+labelOnly = backtickLabel <|> simpleLabel False <?> "label"
+
 label :: Parser Text
 label = (do
     t <- backtickLabel <|> simpleLabel False
@@ -385,16 +396,18 @@
                 FileComponent -> do
                     Text.Megaparsec.takeWhile1P Nothing Dhall.Core.pathCharacter
                 URLComponent -> do
-                    text <- star pchar
-
-                    return (URI.Encode.decodeText text)
+                    star pchar
 
     let quotedPathData = do
             _    <- Text.Parser.Char.char '"'
             text <- Text.Megaparsec.takeWhile1P Nothing quotedPathCharacter
             _    <- Text.Parser.Char.char '"'
 
-            return text
+            case componentType of
+              FileComponent -> do
+                return text
+              URLComponent -> do
+                return (URI.Encode.encodeText text)
 
     quotedPathData <|> pathData
 
@@ -565,9 +578,15 @@
 reserved :: Data.Text.Text -> Parser ()
 reserved x = do _ <- Text.Parser.Char.text x; whitespace
 
+reservedCharOnly :: Char -> Parser ()
+reservedCharOnly c = do _ <- Text.Parser.Char.char c; return ()
+
 reservedChar :: Char -> Parser ()
 reservedChar c = do _ <- Text.Parser.Char.char c; whitespace
 
+keywordOnly :: Data.Text.Text -> Parser ()
+keywordOnly x = try (do _ <- Text.Parser.Char.text x; return ())
+
 keyword :: Data.Text.Text -> Parser ()
 keyword x = try (do _ <- Text.Parser.Char.text x; nonemptyWhitespace)
 
@@ -580,6 +599,9 @@
 _else :: Parser ()
 _else = keyword "else"
 
+_letOnly :: Parser ()
+_letOnly = keywordOnly "let"
+
 _let :: Parser ()
 _let = keyword "let"
 
@@ -598,6 +620,9 @@
 _toMap :: Parser ()
 _toMap = keyword "toMap"
 
+_assert :: Parser ()
+_assert = keyword "assert"
+
 _Some :: Parser ()
 _Some = keyword "Some"
 
@@ -625,6 +650,9 @@
 _NaturalShow :: Parser ()
 _NaturalShow = reserved "Natural/show"
 
+_NaturalSubtract :: Parser ()
+_NaturalSubtract = reserved "Natural/subtract"
+
 _IntegerShow :: Parser ()
 _IntegerShow = reserved "Integer/show"
 
@@ -706,6 +734,9 @@
 _Location :: Parser ()
 _Location = reserved "Location"
 
+_equalOnly :: Parser ()
+_equalOnly = reservedCharOnly '='
+
 _equal :: Parser ()
 _equal = reservedChar '='
 
@@ -766,11 +797,19 @@
 _closeParens :: Parser ()
 _closeParens = reservedChar ')'
 
+_colonOnly :: Parser ()
+_colonOnly = reservedCharOnly ':'
+
 _colon :: Parser ()
 _colon = reservedChar ':'
 
 _at :: Parser ()
 _at = reservedChar '@'
+
+_equivalent :: Parser ()
+_equivalent = do
+    void (Text.Parser.Char.char '≡' <?> "\"≡\"") <|> void (Text.Parser.Char.text "===")
+    whitespace
 
 _missing :: Parser ()
 _missing = reserved "missing"
diff --git a/src/Dhall/Pretty/Internal.hs b/src/Dhall/Pretty/Internal.hs
--- a/src/Dhall/Pretty/Internal.hs
+++ b/src/Dhall/Pretty/Internal.hs
@@ -1,5 +1,7 @@
 {-# LANGUAGE CPP               #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards   #-}
+
 {-# OPTIONS_GHC -Wall #-}
 
 {-| This module provides internal pretty-printing utilities which are used by
@@ -10,6 +12,7 @@
       Ann(..)
     , annToAnsiStyle
     , prettyExpr
+    , prettySrcExpr
 
     , CharacterSet(..)
     , prettyCharacterSet
@@ -67,6 +70,7 @@
 import Data.Text.Prettyprint.Doc (Doc, Pretty, space)
 import Dhall.Map (Map)
 import Dhall.Set (Set)
+import Dhall.Src (Src(..))
 import Numeric.Natural (Natural)
 import Prelude hiding (succ)
 import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Terminal
@@ -108,8 +112,11 @@
 
 -- | Pretty print an expression
 prettyExpr :: Pretty a => Expr s a -> Doc Ann
-prettyExpr = prettyCharacterSet Unicode
+prettyExpr = prettySrcExpr . denote
 
+prettySrcExpr :: Pretty a => Expr Src a -> Doc Ann
+prettySrcExpr = prettyCharacterSet Unicode
+
 {-| Internal utility for pretty-printing, used when generating element lists
     to supply to `enclose` or `enclose'`.  This utility indicates that the
     compact represent is the same as the multi-line representation for each
@@ -118,6 +125,79 @@
 duplicate :: a -> (a, a)
 duplicate x = (x, x)
 
+isWhitespace :: Char -> Bool
+isWhitespace c =
+    case c of
+        ' '  -> True
+        '\n' -> True
+        '\t' -> True
+        '\r' -> True
+        _    -> False
+
+{-| Used to render inline `Src` spans preserved by the syntax tree
+
+    >>> let unusedSourcePos = Text.Megaparsec.SourcePos "" (Text.Megaparsec.mkPos 1) (Text.Megaparsec.mkPos 1)
+    >>> let nonEmptySrc = Src unusedSourcePos unusedSourcePos "-- Documentation for x\n"
+    >>> "let" <> renderSrc (Just nonEmptySrc) " " <> "x = 1 in x"
+    let -- Documentation for x
+        x = 1 in x
+    >>> let emptySrc = Src unusedSourcePos unusedSourcePos "      "
+    >>> "let" <> renderSrc (Just emptySrc) " " <> "x = 1 in x"
+    let x = 1 in x
+    >>> "let" <> renderSrc Nothing " " <> "x = 1 in x"
+    let x = 1 in x
+-}
+renderSrc
+    :: Maybe Src
+    -- ^ Source span to render (if present)
+    -> Doc Ann
+    -- ^ Used as the prefix (when the source span contains a comment) and as a
+    --   fallback (when the source span is absent or comment-free)
+    -> Doc Ann
+renderSrc (Just (Src {..})) prefix
+    | not (Text.all isWhitespace srcText) =
+        prefix <> Pretty.align (Pretty.concatWith f newLines <> suffix)
+  where
+    horizontalSpace c = c == ' ' || c == '\t'
+
+    strippedText = Text.dropAround horizontalSpace srcText
+
+    suffix =
+        if Text.null strippedText
+        then mempty
+        else if Text.last strippedText == '\n' then mempty else " "
+
+    oldLines = Text.splitOn "\n" strippedText
+
+    spacePrefix = Text.takeWhile horizontalSpace
+
+    commonPrefix a b = case Text.commonPrefixes a b of
+        Nothing        -> ""
+        Just (c, _, _) -> c
+
+    blank = Text.all horizontalSpace
+
+    newLines =
+        case oldLines of
+            [] ->
+               []
+            l0 : [] ->
+                Pretty.pretty l0 : []
+            l0 : l1 : ls ->
+                let sharedPrefix =
+                        foldl' commonPrefix (spacePrefix l1) (map spacePrefix (filter (not . blank) ls))
+
+                    perLine l =
+                        case Text.stripPrefix sharedPrefix l of
+                            Nothing -> Pretty.pretty l
+                            Just l' -> Pretty.pretty l'
+
+                in  Pretty.pretty l0 : map perLine (l1 : ls)
+
+    f x y = x <> Pretty.hardline <> y
+renderSrc _ prefix =
+    prefix
+
 -- Annotation helpers
 keyword, syntax, label, literal, builtin, operator :: Doc Ann -> Doc Ann
 keyword  = Pretty.annotate Keyword
@@ -222,6 +302,10 @@
 prefer ASCII   = "//"
 prefer Unicode = "⫽"
 
+equivalent :: CharacterSet -> Text
+equivalent ASCII   = "==="
+equivalent Unicode = "≡"
+
 {-| Format an expression that holds a variable number of elements, such as a
     list, record, or union
 -}
@@ -346,7 +430,20 @@
 prettyVar (V x 0) = label (Pretty.unAnnotate (prettyLabel x))
 prettyVar (V x n) = label (Pretty.unAnnotate (prettyLabel x <> "@" <> prettyInt n))
 
-prettyCharacterSet :: Pretty a => CharacterSet -> Expr s a -> Doc Ann
+{-| Pretty-print an 'Expr' using the given 'CharacterSet'.
+
+'prettyCharacterSet' largely ignores 'Note's. 'Note's do however matter for
+the layout of let-blocks:
+
+>>> let inner = Let (Binding Nothing "x" Nothing Nothing Nothing (NaturalLit 1)) (Var (V "x" 0)) :: Expr Src ()
+>>> prettyCharacterSet ASCII (Let (Binding Nothing "y" Nothing Nothing Nothing (NaturalLit 2)) inner)
+let y = 2 let x = 1 in x
+>>> prettyCharacterSet ASCII (Let (Binding Nothing "y" Nothing Nothing Nothing (NaturalLit 2)) (Note (Src unusedSourcePos unusedSourcePos "") inner))
+let y = 2 in let x = 1 in x
+
+This means the structure of parsed let-blocks is preserved.
+-}
+prettyCharacterSet :: Pretty a => CharacterSet -> Expr Src a -> Doc Ann
 prettyCharacterSet characterSet expression =
     Pretty.group (prettyExpression expression)
   where
@@ -416,45 +513,42 @@
                 ]
         docsShort (Note  _    c) = docsShort c
         docsShort             c  = [ prettyExpression c ]
-    prettyExpression (Let as b) =
+    prettyExpression (Let a0 b0) =
         enclose' "" "" space Pretty.hardline
             (fmap duplicate (fmap docA (toList as)) ++ [ docB ])
       where
-        docA (Binding c Nothing e) =
+        MultiLet as b = multiLet a0 b0
+
+        docA (Binding src0 c src1 Nothing src2 e) =
             Pretty.group (Pretty.flatAlt long short)
           where
             long =  keyword "let" <> space
                 <>  Pretty.align
-                    (   prettyLabel c
-                    <>  space <> equals
-                    <>  Pretty.hardline
-                    <>  "  "
-                    <>  prettyExpression e
+                    (   renderSrc src0 mempty
+                    <>  prettyLabel c <> renderSrc src1 space
+                    <>  equals <> renderSrc src2 Pretty.hardline
+                    <>  "  " <> prettyExpression e
                     )
 
-            short = keyword "let" <> space
-                <>  prettyLabel c
-                <>  (space <> equals <> space)
+            short = keyword "let" <> renderSrc src0 space
+                <>  prettyLabel c <> renderSrc src1 space
+                <>  equals <> renderSrc src2 space
                 <>  prettyExpression e
-        docA (Binding c (Just d) e) =
+        docA (Binding src0 c src1 (Just (src3, d)) src2 e) =
             Pretty.group (Pretty.flatAlt long short)
           where
             long = keyword "let" <> space
                 <>  Pretty.align
-                    (   prettyLabel c
-                    <>  Pretty.hardline
-                    <>  colon <> space
-                    <>  prettyExpression d
-                    <>  Pretty.hardline
-                    <>  equals <> space
+                    (   renderSrc src0 mempty
+                    <>  prettyLabel c <> renderSrc src1 Pretty.hardline
+                    <>  colon <> renderSrc src3 space <> prettyExpression d <> Pretty.hardline <> equals <> renderSrc src2 space
                     <>  prettyExpression e
                     )
 
-            short = keyword "let" <> space
-                <>  prettyLabel c
-                <>  space <> colon <> space
-                <>  prettyExpression d
-                <>  space <> equals <> space
+            short = keyword "let" <> renderSrc src0 space
+                <>  prettyLabel c <> renderSrc src1 space
+                <>  colon <> renderSrc src3 space
+                <>  prettyExpression d <> space <> equals <> renderSrc src2 space
                 <>  prettyExpression e
 
         docB =
@@ -485,12 +579,22 @@
                 <>  rparen
         docs (Note _   c) = docs c
         docs           c  = [ prettyExpression c ]
+    prettyExpression (Assert a) =
+        Pretty.group (Pretty.flatAlt long short)
+      where
+        short = keyword "assert" <> " " <> colon <> " " <> prettyExpression a
+
+        long =
+            Pretty.align
+            (  "  " <> keyword "assert"
+            <> Pretty.hardline <> colon <> " " <> prettyExpression a
+            )
     prettyExpression (Note _ a) =
         prettyExpression a
     prettyExpression a0 =
         prettyAnnotatedExpression a0
 
-    prettyAnnotatedExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyAnnotatedExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyAnnotatedExpression (Merge a b (Just c)) =
         Pretty.group (Pretty.flatAlt long short)
       where
@@ -498,9 +602,9 @@
             Pretty.align
                 (   keyword "merge"
                 <>  Pretty.hardline
-                <>  prettyImportExpression a
+                <>  Pretty.indent 2 (prettyImportExpression a)
                 <>  Pretty.hardline
-                <>  prettyImportExpression b
+                <>  Pretty.indent 2 (prettyImportExpression b)
                 <>  Pretty.hardline
                 <>  colon <> space
                 <>  prettyApplicationExpression c
@@ -519,9 +623,9 @@
             Pretty.align
                 (   keyword "merge"
                 <>  Pretty.hardline
-                <>  prettyImportExpression a
+                <>  Pretty.indent 2 (prettyImportExpression a)
                 <>  Pretty.hardline
-                <>  prettyImportExpression b
+                <>  Pretty.indent 2 (prettyImportExpression b)
                 )
 
         short = keyword "merge" <> space
@@ -535,7 +639,7 @@
             Pretty.align
                 (   keyword "toMap"
                 <>  Pretty.hardline
-                <>  prettyImportExpression a
+                <>  Pretty.indent 2 (prettyImportExpression a)
                 <>  Pretty.hardline
                 <>  colon <> space
                 <>  prettyApplicationExpression b
@@ -552,7 +656,7 @@
             Pretty.align
                 (   keyword "toMap"
                 <>  Pretty.hardline
-                <>  prettyImportExpression a
+                <>  Pretty.indent 2 (prettyImportExpression a)
                 )
 
         short = keyword "toMap" <> space
@@ -577,7 +681,7 @@
     prettyAnnotatedExpression a0 =
         prettyOperatorExpression a0
 
-    prettyOperatorExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyOperatorExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyOperatorExpression = prettyImportAltExpression
 
     prettyOperator :: Text -> [Doc Ann] -> Doc Ann
@@ -593,7 +697,7 @@
 
         spacer = if Text.length op == 1 then " "  else "  "
 
-    prettyImportAltExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyImportAltExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyImportAltExpression a0@(ImportAlt _ _) =
         prettyOperator "?" (docs a0)
       where
@@ -605,7 +709,7 @@
     prettyImportAltExpression a0 =
         prettyOrExpression a0
 
-    prettyOrExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyOrExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyOrExpression a0@(BoolOr _ _) =
         prettyOperator "||" (docs a0)
       where
@@ -617,7 +721,7 @@
     prettyOrExpression a0 =
         prettyPlusExpression a0
 
-    prettyPlusExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyPlusExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyPlusExpression a0@(NaturalPlus _ _) =
         prettyOperator "+" (docs a0)
       where
@@ -629,7 +733,7 @@
     prettyPlusExpression a0 =
         prettyTextAppendExpression a0
 
-    prettyTextAppendExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyTextAppendExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyTextAppendExpression a0@(TextAppend _ _) =
         prettyOperator "++" (docs a0)
       where
@@ -641,7 +745,7 @@
     prettyTextAppendExpression a0 =
         prettyListAppendExpression a0
 
-    prettyListAppendExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyListAppendExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyListAppendExpression a0@(ListAppend _ _) =
         prettyOperator "#" (docs a0)
       where
@@ -653,7 +757,7 @@
     prettyListAppendExpression a0 =
         prettyAndExpression a0
 
-    prettyAndExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyAndExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyAndExpression a0@(BoolAnd _ _) =
         prettyOperator "&&" (docs a0)
       where
@@ -665,7 +769,7 @@
     prettyAndExpression a0 =
        prettyCombineExpression a0
 
-    prettyCombineExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyCombineExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyCombineExpression a0@(Combine _ _) =
         prettyOperator (combine characterSet) (docs a0)
       where
@@ -677,7 +781,7 @@
     prettyCombineExpression a0 =
         prettyPreferExpression a0
 
-    prettyPreferExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyPreferExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyPreferExpression a0@(Prefer _ _) =
         prettyOperator (prefer characterSet) (docs a0)
       where
@@ -689,7 +793,7 @@
     prettyPreferExpression a0 =
         prettyCombineTypesExpression a0
 
-    prettyCombineTypesExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyCombineTypesExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyCombineTypesExpression a0@(CombineTypes _ _) =
         prettyOperator (combineTypes characterSet) (docs a0)
       where
@@ -701,7 +805,7 @@
     prettyCombineTypesExpression a0 =
         prettyTimesExpression a0
 
-    prettyTimesExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyTimesExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyTimesExpression a0@(NaturalTimes _ _) =
         prettyOperator "*" (docs a0)
       where
@@ -713,7 +817,7 @@
     prettyTimesExpression a0 =
         prettyEqualExpression a0
 
-    prettyEqualExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyEqualExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyEqualExpression a0@(BoolEQ _ _) =
         prettyOperator "==" (docs a0)
       where
@@ -725,33 +829,45 @@
     prettyEqualExpression a0 =
         prettyNotEqualExpression a0
 
-    prettyNotEqualExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyNotEqualExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyNotEqualExpression a0@(BoolNE _ _) =
         prettyOperator "!=" (docs a0)
       where
-        docs (BoolNE a b) = prettyApplicationExpression b : docs a
+        docs (BoolNE a b) = prettyEquivalentExpression b : docs a
         docs (Note   _ b) = docs b
-        docs           b  = [ prettyApplicationExpression b ]
+        docs           b  = [ prettyEquivalentExpression b ]
     prettyNotEqualExpression (Note _ a) =
         prettyNotEqualExpression a
     prettyNotEqualExpression a0 =
+        prettyEquivalentExpression a0
+
+    prettyEquivalentExpression :: Pretty a => Expr Src a -> Doc Ann
+    prettyEquivalentExpression a0@(Equivalent _ _) =
+        prettyOperator (equivalent characterSet) (docs a0)
+      where
+        docs (Equivalent a b) = prettyApplicationExpression b : docs a
+        docs (Note       _ b) = docs b
+        docs               b  = [ prettyApplicationExpression b ]
+    prettyEquivalentExpression (Note _ a) =
+        prettyEquivalentExpression a
+    prettyEquivalentExpression a0 =
         prettyApplicationExpression a0
 
-    prettyApplicationExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyApplicationExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyApplicationExpression a0 = case a0 of
         App _ _  -> result
         Some _   -> result
         Note _ b -> prettyApplicationExpression b
         _        -> prettyImportExpression a0
       where
-        result = enclose' "" "" " " "" (fmap duplicate (reverse (docs a0)))
+        result = enclose' "" "" " " "" (reverse (docs a0))
 
-        docs (App  a b) = prettyImportExpression b : docs a
-        docs (Some   a) = [ prettyImportExpression a , builtin "Some"         ]
+        docs (App  a b) = ( prettyImportExpression b, Pretty.indent 2 (prettyImportExpression b) ) : docs a
+        docs (Some   a) = map duplicate [ prettyImportExpression a , builtin "Some" ]
         docs (Note _ b) = docs b
-        docs         b  = [ prettyImportExpression b ]
+        docs         b  = map duplicate [ prettyImportExpression b ]
 
-    prettyImportExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyImportExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyImportExpression (Embed a) =
         Pretty.pretty a
     prettyImportExpression (Note _ a) =
@@ -759,7 +875,7 @@
     prettyImportExpression a0 =
         prettySelectorExpression a0
 
-    prettySelectorExpression :: Pretty a => Expr s a -> Doc Ann
+    prettySelectorExpression :: Pretty a => Expr Src a -> Doc Ann
     prettySelectorExpression (Field a b) =
         prettySelectorExpression a <> dot <> prettyAnyLabel b
     prettySelectorExpression (Project a (Left b)) =
@@ -775,7 +891,7 @@
     prettySelectorExpression a0 =
         prettyPrimitiveExpression a0
 
-    prettyPrimitiveExpression :: Pretty a => Expr s a -> Doc Ann
+    prettyPrimitiveExpression :: Pretty a => Expr Src a -> Doc Ann
     prettyPrimitiveExpression (Var a) =
         prettyVar a
     prettyPrimitiveExpression (Const k) =
@@ -798,6 +914,8 @@
         builtin "Natural/toInteger"
     prettyPrimitiveExpression NaturalShow =
         builtin "Natural/show"
+    prettyPrimitiveExpression NaturalSubtract =
+        builtin "Natural/subtract"
     prettyPrimitiveExpression Integer =
         builtin "Integer"
     prettyPrimitiveExpression IntegerShow =
@@ -855,8 +973,6 @@
         prettyRecordLit a
     prettyPrimitiveExpression (Union a) =
         prettyUnion a
-    prettyPrimitiveExpression (UnionLit a b c) =
-        prettyUnionLit a b c
     prettyPrimitiveExpression (ListLit Nothing b) =
         list (map prettyExpression (Data.Foldable.toList b))
     prettyPrimitiveExpression (Note _ b) =
@@ -870,7 +986,7 @@
 
         short = lparen <> prettyExpression a <> rparen
 
-    prettyKeyValue :: Pretty a => Doc Ann -> (Text, Expr s a) -> (Doc Ann, Doc Ann)
+    prettyKeyValue :: Pretty a => Doc Ann -> (Text, Expr Src a) -> (Doc Ann, Doc Ann)
     prettyKeyValue separator (key, val) =
         (       prettyAnyLabel key
             <>  " "
@@ -885,11 +1001,11 @@
       where
         long = Pretty.hardline <> "    " <> prettyExpression val
 
-    prettyRecord :: Pretty a => Map Text (Expr s a) -> Doc Ann
+    prettyRecord :: Pretty a => Map Text (Expr Src a) -> Doc Ann
     prettyRecord =
         braces . map (prettyKeyValue colon) . Dhall.Map.toList
 
-    prettyRecordLit :: Pretty a => Map Text (Expr s a) -> Doc Ann
+    prettyRecordLit :: Pretty a => Map Text (Expr Src a) -> Doc Ann
     prettyRecordLit a
         | Data.Foldable.null a =
             lbrace <> equals <> rbrace
@@ -899,19 +1015,11 @@
     prettyAlternative (key, Just val) = prettyKeyValue colon (key, val)
     prettyAlternative (key, Nothing ) = duplicate (prettyAnyLabel key)
 
-    prettyUnion :: Pretty a => Map Text (Maybe (Expr s a)) -> Doc Ann
+    prettyUnion :: Pretty a => Map Text (Maybe (Expr Src a)) -> Doc Ann
     prettyUnion =
         angles . map prettyAlternative . Dhall.Map.toList
 
-    prettyUnionLit
-        :: Pretty a
-        => Text -> Expr s a -> Map Text (Maybe (Expr s a)) -> Doc Ann
-    prettyUnionLit a b c =
-        angles (front : map prettyAlternative (Dhall.Map.toList c))
-      where
-        front = prettyKeyValue equals (a, b)
-
-    prettyChunks :: Pretty a => Chunks s a -> Doc Ann
+    prettyChunks :: Pretty a => Chunks Src a -> Doc Ann
     prettyChunks (Chunks a b) =
         if any (\(builder, _) -> hasNewLine builder) a || hasNewLine b
         then Pretty.flatAlt long short
diff --git a/src/Dhall/Repl.hs b/src/Dhall/Repl.hs
--- a/src/Dhall/Repl.hs
+++ b/src/Dhall/Repl.hs
@@ -19,15 +19,14 @@
 -- For the MonadFail instance for StateT.
 import Control.Monad.Trans.Instances ()
 import Data.List ( isPrefixOf, nub )
-import Data.List.NonEmpty (NonEmpty(..))
 import Data.Maybe ( mapMaybe )
 import Data.Semigroup ((<>))
 import Data.Text ( Text )
-import Dhall.Binary (StandardVersion(..))
+import Data.Version (showVersion)
 import Dhall.Context (Context)
-import Dhall.Import (hashExpressionToCode, standardVersion)
+import Dhall.Import (hashExpressionToCode)
+import Dhall.Src (Src)
 import Dhall.Pretty (CharacterSet(..))
-import Lens.Family (set)
 import System.Console.Haskeline (Interrupt(..))
 import System.Console.Haskeline.Completion ( Completion, simpleCompletion )
 import System.Directory ( getDirectoryContents )
@@ -41,7 +40,6 @@
 import qualified Data.Text.Prettyprint.Doc as Pretty
 import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty ( renderIO )
 import qualified Dhall
-import qualified Dhall.Binary
 import qualified Dhall.Context
 import qualified Dhall.Core
 import qualified Dhall.Core as Dhall ( Var(V), Expr, normalize )
@@ -51,6 +49,7 @@
 import qualified Dhall.Map as Map
 import qualified Dhall.Parser as Dhall
 import qualified Dhall.TypeCheck as Dhall
+import qualified Paths_dhall as Meta
 import qualified System.Console.ANSI
 import qualified System.Console.Haskeline.Completion as Haskeline
 import qualified System.Console.Haskeline.MonadException as Haskeline
@@ -60,8 +59,8 @@
 type Repl = Repline.HaskelineT (State.StateT Env IO)
 
 -- | Implementation of the @dhall repl@ subcommand
-repl :: CharacterSet -> Bool -> StandardVersion -> IO ()
-repl characterSet explain _standardVersion =
+repl :: CharacterSet -> Bool -> IO ()
+repl characterSet explain =
     if explain then Dhall.detailed io else io
   where
     io =
@@ -74,7 +73,7 @@
             completer
             greeter
         )
-        (emptyEnv { characterSet, explain, _standardVersion })
+        (emptyEnv { characterSet, explain })
 
 
 data Env = Env
@@ -82,7 +81,6 @@
   , envIt            :: Maybe Binding
   , explain          :: Bool
   , characterSet     :: CharacterSet
-  , _standardVersion :: StandardVersion
   , outputHandle     :: Maybe System.IO.Handle
   }
 
@@ -93,7 +91,6 @@
     { envBindings = Dhall.Context.empty
     , envIt = Nothing
     , explain = False
-    , _standardVersion = Dhall.Binary.defaultStandardVersion
     , characterSet = Unicode
     , outputHandle = Just System.IO.stdout
     }
@@ -116,12 +113,8 @@
 
 
 parseAndLoad
-  :: ( MonadIO m, MonadState Env m )
-  => String -> m ( Dhall.Expr Dhall.Src Dhall.X )
+  :: MonadIO m => String -> m ( Dhall.Expr Dhall.Src Dhall.X )
 parseAndLoad src = do
-  env <-
-    get
-
   parsed <-
     case Dhall.exprFromText "(stdin)" ( Text.pack src ) of
       Left e ->
@@ -130,8 +123,7 @@
       Right a ->
         return a
 
-  let status =
-        set standardVersion (_standardVersion env) (Dhall.emptyStatus ".")
+  let status = Dhall.emptyStatus "."
 
   liftIO ( State.evalStateT (Dhall.loadWith parsed) status )
 
@@ -174,16 +166,12 @@
     -> Dhall.Expr Dhall.Src Dhall.X
     -> Dhall.Expr Dhall.Src Dhall.X
 applyContext context expression =
-  case bindings of
-    []     -> expression
-    b : bs -> Dhall.Core.Let (b :| bs) expression
+    Dhall.Core.wrapInLets bindings expression
   where
     definitions = reverse $ Dhall.Context.toList context
 
-    convertBinding (variable, Binding {..}) = Dhall.Core.Binding {..}
-      where
-        annotation = Just bindingType
-        value      = bindingExpr
+    convertBinding (variable, Binding expr type_) =
+        Dhall.Core.Binding Nothing variable Nothing (Just (Nothing, type_)) Nothing expr
 
     bindings = fmap convertBinding definitions
 
@@ -267,9 +255,7 @@
 
   normalizedExpression <- normalize loadedExpression
 
-  Env{_standardVersion} <- get
-
-  writeOutputHandle $ hashExpressionToCode _standardVersion normalizedExpression
+  writeOutputHandle $ hashExpressionToCode normalizedExpression
 
 saveFilePrefix :: FilePath
 saveFilePrefix = ".dhall-repl"
@@ -410,26 +396,90 @@
   liftIO (putStrLn "Goodbye.")
   liftIO (throwIO Interrupt)
 
+help
+  :: ( Haskeline.MonadException m, MonadFail m, MonadIO m, MonadState Env m )
+  => HelpOptions m -> [String] -> m ()
+help hs _ = do
+  liftIO (putStrLn "Type any expression to normalize it or use one of the following commands:")
+  forM_ hs $ \h -> do
+    let name = helpOptionName h
+        syntax = helpOptionSyntax h
+        doc = helpOptionDoc h
+    liftIO (putStrLn (":" <> name <> " " <> syntax))
+    liftIO (putStrLn ("    " <> doc))
 
 optionsPrefix :: Char
 optionsPrefix = ':'
 
+data HelpOption m = HelpOption
+  { helpOptionName :: String
+  , helpOptionSyntax :: String
+  , helpOptionDoc :: String
+  , helpOptionFunction :: Repline.Cmd m
+  }
 
-options
+type HelpOptions m = [HelpOption m]
+
+helpOptions
   :: ( Haskeline.MonadException m, MonadFail m, MonadIO m, MonadState Env m )
-  => Repline.Options m
-options =
-  [ ( "type", dontCrash . typeOf )
-  , ( "hash", dontCrash . hashBinding )
-  , ( "let", dontCrash . addBinding . separateEqual )
-  , ( "clear", dontCrash . clearBindings)
-  , ( "load", dontCrash . loadBinding )
-  , ( "save", dontCrash . saveBinding . separateEqual )
-  , ( "set", dontCrash . setOption)
-  , ( "unset", dontCrash . unsetOption)
-  , ( "quit", cmdQuit )
+  => HelpOptions m
+helpOptions =
+  [ HelpOption
+      "help"
+      ""
+      "Print help text and describe options"
+      (dontCrash . help helpOptions)
+  , HelpOption
+      "type"
+      "EXPRESSION"
+      "Infer the type of an expression"
+      (dontCrash . typeOf)
+  , HelpOption
+      "hash"
+      "EXPRESSION"
+      "Hash the normalized value of an expression"
+      (dontCrash . hashBinding)
+  , HelpOption
+      "let"
+      "IDENTIFIER = EXPRESSION"
+      "Assign an expression to a variable"
+      (dontCrash . addBinding . separateEqual)
+  , HelpOption
+      "clear"
+      ""
+      "Clear all bound variables"
+      (dontCrash . clearBindings)
+  , HelpOption
+      "load"
+      "[FILENAME]"
+      "Load bound variables from a file"
+      (dontCrash . loadBinding)
+  , HelpOption
+      "save"
+      "[FILENAME | FILENAME = EXPRESSION]"
+      "Save bound variables or a given expression to a file"
+      (dontCrash . saveBinding . separateEqual)
+  , HelpOption
+      "set"
+      "OPTION"
+      "Set an option. Currently supported: --explain"
+      (dontCrash . setOption)
+  , HelpOption
+      "unset"
+      "OPTION"
+      "Unset an option"
+      (dontCrash . unsetOption)
+  , HelpOption
+      "quit"
+      ""
+      "Exit the REPL"
+      cmdQuit
   ]
 
+options
+  :: ( Haskeline.MonadException m, MonadFail m, MonadIO m, MonadState Env m )
+  => Repline.Options m
+options = (\h -> (helpOptionName h, helpOptionFunction h)) <$> helpOptions
 
 completer
   :: (Monad m, MonadFail m, MonadIO m, MonadState Env m)
@@ -519,7 +569,9 @@
 
 greeter :: MonadIO m => m ()
 greeter =
-  return ()
+  let version = showVersion Meta.version
+      message = "Welcome to the Dhall v" <> version <> " REPL! Type :help for more information."
+  in liftIO (putStrLn message)
 
 
 dontCrash :: ( MonadIO m, Haskeline.MonadException m ) => m () -> m ()
@@ -538,7 +590,7 @@
 
 output
   :: (Pretty.Pretty a, MonadState Env m, MonadIO m)
-  => Dhall.Expr s a -> m ()
+  => Dhall.Expr Src a -> m ()
 output expr = do
   writeOutputHandle "" -- Visual spacing
 
@@ -548,7 +600,7 @@
 
 outputWithoutSpacing
   :: (Pretty.Pretty a, MonadState Env m, MonadIO m)
-  => Dhall.Expr s a -> m ()
+  => Dhall.Expr Src a -> m ()
 outputWithoutSpacing expr = do
   Env { characterSet, outputHandle } <- get
 
diff --git a/src/Dhall/Set.hs b/src/Dhall/Set.hs
--- a/src/Dhall/Set.hs
+++ b/src/Dhall/Set.hs
@@ -35,13 +35,23 @@
 import qualified Data.Sequence
 import qualified Data.Foldable
 
+-- Invariant: In @Set set seq@, @toAscList set == sort (toList seq)@.
 data Set a = Set (Data.Set.Set a) (Seq a)
-    deriving (Eq, Generic, Ord, Show, Data, NFData)
+    deriving (Generic, Show, Data, NFData)
 
+instance Eq a => Eq (Set a) where
+    (Set _ x) == (Set _ y) = x == y
+    {-# INLINABLE (==) #-}
+
+instance Ord a => Ord (Set a) where
+    compare (Set _ x) (Set _ y) = compare x y
+    {-# INLINABLE compare #-}
+
 instance (Data a, Lift a, Ord a) => Lift (Set a)
 
 instance Foldable Set where
-    foldMap f = foldMap f . toSeq
+    foldMap f (Set _ x) = foldMap f x
+    {-# INLINABLE foldMap #-}
 
 toSet :: Set a -> Data.Set.Set a
 toSet (Set s _) = s
diff --git a/src/Dhall/Src.hs b/src/Dhall/Src.hs
--- a/src/Dhall/Src.hs
+++ b/src/Dhall/Src.hs
@@ -28,9 +28,11 @@
 import qualified Text.Printf     as Printf
 
 -- | Source code extract
-data Src = Src !SourcePos !SourcePos Text
-  -- Text field is intentionally lazy
-  deriving (Data, Eq, Generic, Ord, Show, NFData)
+data Src = Src
+    { srcStart :: !SourcePos
+    , srcEnd   :: !SourcePos
+    , srcText  :: Text -- Text field is intentionally lazy
+    } deriving (Data, Eq, Generic, Ord, Show, NFData)
 
 
 instance Lift Src where
diff --git a/src/Dhall/Tutorial.hs b/src/Dhall/Tutorial.hs
--- a/src/Dhall/Tutorial.hs
+++ b/src/Dhall/Tutorial.hs
@@ -47,6 +47,9 @@
     -- * Total
     -- $total
 
+    -- * Assertions
+    -- $assertions
+
     -- * Headers
     -- $headers
 
@@ -1386,6 +1389,90 @@
 -- finding an input expression that crashes or loops forever (and file a bug
 -- report if you succeed)
 
+-- $assertions
+--
+-- You can add compile-time assertions which you can use to add tests to your
+-- code.  For example, we can add some tests to our @not@ function like this:
+--
+-- > let not : Bool -> Bool = \(b : Bool) -> b == False
+-- >
+-- > let example0 = assert : not False === True
+-- >
+-- > let example1 = assert : not True === False
+-- >
+-- > in  not
+--
+-- The expression @assert : not False == True@ is a type-checking assertion
+-- that two expressions have the same normal form.  If the two expressions differ
+-- then type-checking rejects the code.
+--
+-- For example, suppose that we change the example to add an incorrect assertion:
+--
+-- > -- ./test.dhall
+-- >
+-- > let not : Bool -> Bool = \(b : Bool) -> b == False
+-- >
+-- > let example0 = assert : not False === True
+-- >
+-- > let example1 = assert : not True === True  -- Oops!
+-- >
+-- > in  not
+--
+-- The type-checker then rejects the assertion with the following error message:
+--
+-- > $ dhall <<< './test.dhall' 
+-- > 
+-- > ↳ ./test.dhall
+-- > 
+-- > Error: Assertion failed
+-- > 
+-- > - False
+-- > + True
+-- > 
+-- > 7│                assert : not True === True -- Oops!
+-- > 8│ 
+-- > 
+-- > ./test.dhall:7:16
+-- > 
+-- > 1│ ./test.dhall
+-- > 
+-- > (stdin):1:1
+--
+-- You can compare expressions that contain variables, too, which is equivalent
+-- to symbolic reasoning:
+--
+-- > $ dhall <<< '\(n : Natural) -> assert : n === (n + 0)'
+-- > λ(n : Natural) → assert : n ≡ n
+--
+-- Dhall accepts this because the language has built-in support for normalizing
+-- @n + 0@ to @n@, so both sides of the comparison normalize to the same value:
+-- @n@.
+--
+-- Note that this sort of symbolic reasoning is limited and can only detect
+-- equality of normal forms.  Some equivalent expressions will be rejected
+-- if they don't share the same normal form, such as these:
+--
+-- > $ dhall <<< '\(n : Natural) -> assert : Natural/even (n + n) === True'
+-- > 
+-- > Use "dhall --explain" for detailed errors
+-- > 
+-- > n : Natural
+-- > 
+-- > Error: Assertion failed
+-- > 
+-- > - … …
+-- > + True
+-- > 
+-- > 1│                   assert : Natural/even (n + n) === True
+-- > 
+-- > (stdin):1:19
+--
+-- Here the normalizer is not smart enough to simplify @Natural/even (n + n)@ to
+-- @True@ so the assertion fails.
+--
+-- If you prefer to use Unicode, then the Unicode equivalent of @===@ is @≡@
+-- (U+2261).
+
 -- $headers
 --
 -- Sometimes you would like to provide additional request headers when importing
@@ -1440,7 +1527,7 @@
 -- For example, suppose you save the following two files:
 --
 -- > $ cat ./foo
--- > ./bar sha256:6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b
+-- > ./bar sha256:d60d8415e36e86dae7f42933d3b0c4fe3ca238f057fba206c7e9fbf5d784fe15
 --
 -- > $ cat ./bar
 -- > ./baz
@@ -1463,9 +1550,40 @@
 -- > 
 -- > 1
 --
--- This implies that the hash only changes if the Dhall value changes.  For
--- example, if you add a comment to the @./bar@ file:
+-- Any import protected by a semantic integrity check is automatically cached
+-- locally underneath either @~\/.cache\/dhall\/1220${HASH}@ or
+-- @${XDG_CACHE_HOME}\/dhall/1220${HASH}@ if you define the @XDG_CACHE_HOME@
+-- environment variable.
 --
+-- For example, after you import @./foo@ the contents of `./bar` are locally
+-- cached in a fully-evaluated and binary-encoded form which you can inspect by
+-- running:
+--
+-- > $ dhall decode < ~/.cache/dhall/1220d60d8415e36e86dae7f42933d3b0c4fe3ca238f057fba206c7e9fbf5d784fe15
+-- > 1
+--
+-- Subsequent attempts to resolve the same import will automatically retrieve
+-- the import from the cache.  This matters less for local imports, but comes in
+-- handy for remote imports to avoid redownloading them.
+--
+-- The local cache takes precedence when resolving imports, so changing the
+-- original import afterwards will have no affect until you update the hash.
+-- From Dhall's point of view, the hash is the true address and the file path
+-- is just a suggestion for how to obtain the import if it's not already cached.
+--
+-- You can disable the cache by setting `XDG_CACHE_HOME` to `/var/empty` (an
+-- empty and unwritable directory), like this:
+--
+-- > $ XDG_CACHE_HOME=/var/empty dhall <<< './foo'
+-- > Natural
+-- > 
+-- > 1
+--
+-- We'll use this trick to test changes to the protected import in the following
+-- examples.
+--
+-- Now, supose you add a comment to the @./bar@ file:
+--
 -- > $ cat ./bar
 -- > -- This comment does not change the hash
 -- > ./baz
@@ -1474,7 +1592,7 @@
 -- only depends on the normalized value and does not depend on meaningless
 -- changes to whitespace or comments:
 --
--- > $ dhall <<< './foo'  # This still succeeds
+-- > $ XDG_CACHE_HOME=/var/empty dhall <<< './foo'  # This still succeeds
 -- > Natural
 -- > 
 -- > 1
@@ -1482,12 +1600,10 @@
 -- You can compute the Hash for any import by using the hash subcommand 
 -- of this package.  For example:
 --
--- > dhall hash <<< './bar'
--- > sha256:6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b
---
--- Then you can paste that output into your code after the import
+-- > $ dhall hash <<< './bar'
+-- > sha256:d60d8415e36e86dae7f42933d3b0c4fe3ca238f057fba206c7e9fbf5d784fe15
 --
--- Now suppose that you you change the value of the @./baz@ file:
+-- Now suppose that you actually change the value of the @./baz@ file:
 --
 -- > $ cat ./baz
 -- > 2
@@ -1495,26 +1611,27 @@
 -- ... then the @./foo@ file will fail to import @./bar@, even though the
 -- text of the @./bar@ file technically never changed:
 --
--- > dhall <<< './foo'
+-- > XDG_CACHE_HOME=/var/empty dhall <<< './foo'
 -- > 
 -- > Error: Import integrity check failed
 -- > 
 -- > Expected hash:
 -- > 
--- > ↳ 6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b
+-- > ↳ d60d8415e36e86dae7f42933d3b0c4fe3ca238f057fba206c7e9fbf5d784fe15
 -- > 
 -- > Actual hash:
 -- > 
--- > ↳ d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35
+-- > ↳ 4caf97e8c445d4d4b5c5b992973e098ed4ae88a355915f5a59db640a589bc9cb
 --
 -- This is because the @./bar@ file now represents a new value (@2@ instead of
--- @1@), even though the text of the @./bar@ is still the same.  Since the value
--- changed the hash must change as well.  However, we could change @./baz@ to:
+-- @1@), even though the text of the @./bar@ file is still the same.  Since the
+-- value changed the hash must change as well.  However, we could change @./baz@
+-- to:
 --
 -- > $ cat baz
 -- > if True then 1 else 2
 --
--- ... and the import would succeed again because the final result is still @1@.
+-- ... and the import would now succeed again because the final result is @1@.
 --
 -- The integrity hash ensures that your import's final meaning can never change,
 -- so an attacker can never compromise an imported value protected by a hash
@@ -1542,7 +1659,7 @@
 -- > let replicate =
 -- >       https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate sha256:b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ad
 -- > in  replicate 5
---
+
 -- $rawText
 --
 -- Sometimes you want to import the contents of a raw text file as a Dhall
diff --git a/src/Dhall/TypeCheck.hs b/src/Dhall/TypeCheck.hs
--- a/src/Dhall/TypeCheck.hs
+++ b/src/Dhall/TypeCheck.hs
@@ -15,18 +15,21 @@
 
     -- * Types
     , Typer
-    , X(..)
+    , X
+    , absurd
     , TypeError(..)
     , DetailedTypeError(..)
     , TypeMessage(..)
     ) where
 
+import Data.Void (Void, absurd)
 import Control.Exception (Exception)
+import Control.Monad.Trans.Class (lift)
+import Control.Monad.Trans.Writer.Strict (execWriterT, tell)
 import Data.Functor (void)
-import Data.List.NonEmpty (NonEmpty(..))
 import Data.Monoid (Endo(..), First(..))
 import Data.Sequence (Seq, ViewL(..))
-import Data.Semigroup (Semigroup(..))
+import Data.Semigroup (Max(..), Semigroup(..))
 import Data.Set (Set)
 import Data.Text (Text)
 import Data.Text.Prettyprint.Doc (Doc, Pretty(..))
@@ -35,7 +38,6 @@
 import Dhall.Core (Binding(..), Const(..), Chunks(..), Expr(..), Var(..))
 import Dhall.Context (Context)
 import Dhall.Pretty (Ann, layoutOpts)
-import Dhall.X (X(..))
 
 import qualified Data.Foldable
 import qualified Data.Map
@@ -52,6 +54,8 @@
 import qualified Dhall.Pretty.Internal
 import qualified Dhall.Util
 
+type X = Void
+
 traverseWithIndex_ :: Applicative f => (Int -> a -> f b) -> Seq a -> f ()
 traverseWithIndex_ k xs =
     Data.Foldable.sequenceA_ (Data.Sequence.mapWithIndex k xs)
@@ -61,16 +65,16 @@
 axiom Kind = return Sort
 axiom Sort = Left (TypeError Dhall.Context.empty (Const Sort) Untyped)
 
-rule :: Const -> Const -> Either () Const
-rule Type Type = return Type
-rule Kind Type = return Type
-rule Sort Type = return Type
-rule Kind Kind = return Kind
-rule Sort Kind = return Sort
-rule Sort Sort = return Sort
--- This forbids dependent types. If this ever changes, then the fast
--- path in the Let case of typeWithA will become unsound.
-rule _    _    = Left ()
+rule :: Const -> Const -> Const
+rule Type Type = Type
+rule Kind Type = Type
+rule Sort Type = Type
+rule Type Kind = Kind
+rule Kind Kind = Kind
+rule Sort Kind = Sort
+rule Type Sort = Sort
+rule Kind Sort = Sort
+rule Sort Sort = Sort
 
 {-| Type-check an expression and return the expression's type if type-checking
     succeeds or an error if type-checking fails
@@ -131,9 +135,7 @@
             Const k -> return k
             _       -> Left (TypeError ctx' e (InvalidOutputType _B))
 
-        case rule kA kB of
-            Left () -> Left (TypeError ctx e (NoDependentTypes _A _B))
-            Right k -> Right (Const k)
+        return (Const (rule kA kB))
     loop ctx e@(App f a         ) = do
         tf <- fmap Dhall.Core.normalize (loop ctx f)
         (x, _A, _B) <- case tf of
@@ -150,10 +152,10 @@
                 let nf_A  = Dhall.Core.normalize _A
                 let nf_A' = Dhall.Core.normalize _A'
                 Left (TypeError ctx e (TypeMismatch f nf_A a nf_A'))
-    loop ctx e@(Let (Binding x mA a0 :| ls) b0) = do
+    loop ctx e@(Let (Binding _ x _ mA _ a0) b0) = do
         _A1 <- loop ctx a0
         case mA of
-            Just _A0 -> do
+            Just (_, _A0) -> do
                 _ <- loop ctx _A0
                 let nf_A0 = Dhall.Core.normalize _A0
                 let nf_A1 = Dhall.Core.normalize _A1
@@ -162,36 +164,12 @@
                     else Left (TypeError ctx e (AnnotMismatch a0 nf_A0 nf_A1))
             Nothing -> return ()
 
-        t <- loop ctx _A1
-
         let a1 = Dhall.Core.normalize a0
         let a2 = Dhall.Core.shift 1 (V x 0) a1
 
-        let rest = case ls of
-                []       -> b0
-                l' : ls' -> Let (l' :| ls') b0
-
-        -- The catch-all branch directly implements the Dhall
-        -- specification as written; it is necessary to substitute in
-        -- types in order to get 'dependent let' behaviour and to
-        -- allow type synonyms (see #69). However, doing a full
-        -- substitution is slow if the value is large and used many
-        -- times. If the value being substitued in is a term (i.e.,
-        -- its type is a Type), then we can get a very significant
-        -- speed-up by doing the type-checking once at binding-time,
-        -- as opposed to doing it at every use site (see #412).
-        case Dhall.Core.normalize t of
-          Const Type -> do
-            let ctx' = fmap (Dhall.Core.shift 1 (V x 0)) (Dhall.Context.insert x (Dhall.Core.normalize _A1) ctx)
-            _B0 <- loop ctx' rest
-            let _B1 = Dhall.Core.subst (V x 0) a2 _B0
-            let _B2 = Dhall.Core.shift (-1) (V x 0) _B1
-            return _B2
-
-          _ -> do
-            let b1 = Dhall.Core.subst (V x 0) a2 rest
-            let b2 = Dhall.Core.shift (-1) (V x 0) b1
-            loop ctx b2
+        let b1 = Dhall.Core.subst (V x 0) a2 b0
+        let b2 = Dhall.Core.shift (-1) (V x 0) b1
+        loop ctx b2
 
     loop ctx e@(Annot x t       ) = do
         case Dhall.Core.denote t of
@@ -306,6 +284,8 @@
         return (Pi "_" Natural Integer)
     loop _      NaturalShow  = do
         return (Pi "_" Natural Text)
+    loop _      NaturalSubtract  = do
+        return (Pi "_" Natural (Pi "_" Natural Natural))
     loop ctx e@(NaturalPlus  l r) = do
         tl <- fmap Dhall.Core.normalize (loop ctx l)
         case tl of
@@ -474,47 +454,22 @@
                       (Pi "just" (Pi "_" "a" "optional")
                           (Pi "nothing" "optional" "optional") )
     loop ctx e@(Record    kts   ) = do
-        case Dhall.Map.uncons kts of
-            Nothing             -> return (Const Type)
-            Just (k0, t0, rest) -> do
-                s0 <- fmap Dhall.Core.normalize (loop ctx t0)
-                c <- case s0 of
-                    Const c -> pure c
-                    _ -> Left (TypeError ctx e (InvalidFieldType k0 t0))
-                let process k t = do
-                        s <- fmap Dhall.Core.normalize (loop ctx t)
-                        case s of
-                            Const c' ->
-                                if c == c'
-                                then return ()
-                                else Left (TypeError ctx e (FieldAnnotationMismatch k t c k0 t0 c'))
-                            _ -> Left (TypeError ctx e (InvalidFieldType k t))
-                Dhall.Map.unorderedTraverseWithKey_ process rest
-                return (Const c)
+        let process k t = do
+                s <- lift (fmap Dhall.Core.normalize (loop ctx t))
+                case s of
+                    Const c -> tell (Max c)
+                    _ -> lift (Left (TypeError ctx e (InvalidFieldType k t)))
+        Max c <- execWriterT (Dhall.Map.unorderedTraverseWithKey_ process kts)
+        return (Const c)
     loop ctx e@(RecordLit kvs   ) = do
-        case Dhall.Map.uncons kvs of
-            Nothing             -> return (Record mempty)
-            Just (k0, v0, kvs') -> do
-                t0 <- loop ctx v0
-                s0 <- fmap Dhall.Core.normalize (loop ctx t0)
-                c <- case s0 of
-                    Const c -> pure c
-                    _       -> Left (TypeError ctx e (InvalidFieldType k0 v0))
-
-                let process k v = do
-                        t <- loop ctx v
-                        s <- fmap Dhall.Core.normalize (loop ctx t)
-                        case s of
-                            Const c'
-                                | c == c'   -> return ()
-                                | otherwise -> Left (TypeError ctx e (FieldMismatch k v c k0 v0 c'))
-                            _ -> Left (TypeError ctx e (InvalidFieldType k t))
-
-                        return t
-
-                kts <- Dhall.Map.unorderedTraverseWithKey process kvs'
+        let process k v = do
+                t <- loop ctx v
+                s <- fmap Dhall.Core.normalize (loop ctx t)
+                case s of
+                    Const _ -> return t
+                    _ -> Left (TypeError ctx e (InvalidFieldType k t))
 
-                return (Record (Dhall.Map.insert k0 t0 kts))
+        Record <$> Dhall.Map.unorderedTraverseWithKey process kvs
     loop ctx e@(Union     kts   ) = do
         let nonEmpty k mt = First (fmap (\t -> (k, t)) mt)
 
@@ -552,14 +507,6 @@
                 Dhall.Map.unorderedTraverseWithKey_ process (Dhall.Map.delete k0 kts)
 
                 return (Const c0)
-    loop ctx e@(UnionLit k v kts) = do
-        case Dhall.Map.lookup k kts of
-            Just _  -> Left (TypeError ctx e (DuplicateAlternative k))
-            Nothing -> return ()
-        t <- loop ctx v
-        let union = Union (Dhall.Map.insert k (Just (Dhall.Core.normalize t)) kts)
-        _ <- loop ctx union
-        return union
     loop ctx e@(Combine kvsX kvsY) = do
         tKvsX <- fmap Dhall.Core.normalize (loop ctx kvsX)
         ktsX  <- case tKvsX of
@@ -571,20 +518,6 @@
             Record kts -> return kts
             _          -> Left (TypeError ctx e (MustCombineARecord '∧' kvsY tKvsY))
 
-        ttKvsX <- fmap Dhall.Core.normalize (loop ctx tKvsX)
-        constX <- case ttKvsX of
-            Const constX -> return constX
-            _            -> Left (TypeError ctx e (MustCombineARecord '∧' kvsX tKvsX))
-
-        ttKvsY <- fmap Dhall.Core.normalize (loop ctx tKvsY)
-        constY <- case ttKvsY of
-            Const constY -> return constY
-            _            -> Left (TypeError ctx e (MustCombineARecord '∧' kvsY tKvsY))
-
-        if constX == constY
-            then return ()
-            else Left (TypeError ctx e (RecordMismatch '∧' kvsX kvsY constX constY))
-
         let combineTypes ktsL ktsR = do
                 let combine _ (Record ktsL') (Record ktsR') = combineTypes ktsL' ktsR'
                     combine k _ _ = Left (TypeError ctx e (FieldCollision k))
@@ -606,15 +539,7 @@
         cR <- case tR of
             Const cR -> return cR
             _        -> Left (TypeError ctx e (CombineTypesRequiresRecordType r r'))
-        let decide Type Type =
-                return Type
-            decide Kind Kind =
-                return Kind
-            decide Sort Sort =
-                return Sort
-            decide x y =
-                Left (TypeError ctx e (RecordTypeMismatch x y l r))
-        c <- decide cL cR
+        let c = max cL cR
 
         ktsL0 <- case l' of
             Record kts -> return kts
@@ -646,20 +571,6 @@
             Record kts -> return kts
             _          -> Left (TypeError ctx e (MustCombineARecord '⫽' kvsY tKvsY))
 
-        ttKvsX <- fmap Dhall.Core.normalize (loop ctx tKvsX)
-        constX <- case ttKvsX of
-            Const constX -> return constX
-            _            -> Left (TypeError ctx e (MustCombineARecord '⫽' kvsX tKvsX))
-
-        ttKvsY <- fmap Dhall.Core.normalize (loop ctx tKvsY)
-        constY <- case ttKvsY of
-            Const constY -> return constY
-            _            -> Left (TypeError ctx e (MustCombineARecord '⫽' kvsY tKvsY))
-
-        if constX == constY
-            then return ()
-            else Left (TypeError ctx e (RecordMismatch '⫽' kvsX kvsY constX constY))
-
         return (Record (Dhall.Map.union ktsY ktsX))
     loop ctx e@(Merge kvsX kvsY mT₁) = do
         tKvsX <- fmap Dhall.Core.normalize (loop ctx kvsX)
@@ -755,6 +666,12 @@
             Record kts -> return kts
             _          -> Left (TypeError ctx e (MustMapARecord kvsX tKvsX))
 
+        _TKvsX <- loop ctx tKvsX
+
+        case _TKvsX of
+            Const Type -> return ()
+            kind       -> Left (TypeError ctx e (InvalidToMapRecordKind tKvsX kind))
+
         Data.Foldable.traverse_ (loop ctx) mT₁
 
         let ktX = appEndo (foldMap (Endo . compareFieldTypes) ktsX) Nothing
@@ -853,6 +770,41 @@
                 let text = Dhall.Core.pretty t
 
                 Left (TypeError ctx e (CantProject text r t))
+    loop ctx e@(Assert t) = do
+        _ <- loop ctx t
+
+        let t' = Dhall.Core.normalize t
+
+        case t' of
+            Equivalent x y -> do
+                if Dhall.Core.judgmentallyEqual x y
+                    then return t'
+                    else Left (TypeError ctx e (AssertionFailed x y))
+
+            _ -> Left (TypeError ctx e (NotAnEquivalence t))
+    loop ctx e@(Equivalent x y) = do
+        _A₀ <- loop ctx x
+
+        c₀ <- loop ctx _A₀
+        case c₀ of
+            Const Type -> return ()
+            _          -> Left (TypeError ctx e (IncomparableExpression x))
+
+        _A₁ <- loop ctx y
+
+        c₁ <- loop ctx _A₁
+        case c₁ of
+            Const Type -> return ()
+            _          -> Left (TypeError ctx e (IncomparableExpression y))
+
+        if Dhall.Core.judgmentallyEqual _A₀ _A₁
+            then return ()
+            else do
+                let nf_A₀ = Dhall.Core.normalize _A₀
+                let nf_A₁ = Dhall.Core.normalize _A₁
+                Left (TypeError ctx e (EquivalenceTypeMismatch x nf_A₀ y nf_A₁))
+
+        return (Const Type)
     loop ctx   (Note s e'       ) = case loop ctx e' of
         Left (TypeError ctx' (Note s' e'') m) -> Left (TypeError ctx' (Note s' e'') m)
         Left (TypeError ctx'          e''  m) -> Left (TypeError ctx' (Note s  e'') m)
@@ -886,21 +838,17 @@
     | IfBranchMismatch (Expr s a) (Expr s a) (Expr s a) (Expr s a)
     | IfBranchMustBeTerm Bool (Expr s a) (Expr s a) (Expr s a)
     | InvalidFieldType Text (Expr s a)
-    | FieldAnnotationMismatch Text (Expr s a) Const Text (Expr s a) Const
-    | FieldMismatch Text (Expr s a) Const Text (Expr s a) Const
-    | InvalidAlternative Text (Expr s a)
     | InvalidAlternativeType Text (Expr s a)
     | AlternativeAnnotationMismatch Text (Expr s a) Const Text (Expr s a) Const
     | ListAppendMismatch (Expr s a) (Expr s a)
-    | DuplicateAlternative Text
     | MustCombineARecord Char (Expr s a) (Expr s a)
-    | RecordMismatch Char (Expr s a) (Expr s a) Const Const
     | CombineTypesRequiresRecordType (Expr s a) (Expr s a)
     | RecordTypeMismatch Const Const (Expr s a) (Expr s a)
     | FieldCollision Text
     | MustMergeARecord (Expr s a) (Expr s a)
     | MustMergeUnion (Expr s a) (Expr s a)
     | MustMapARecord (Expr s a) (Expr s a)
+    | InvalidToMapRecordKind (Expr s a) (Expr s a)
     | HeterogenousRecordToMap (Expr s a) (Expr s a) (Expr s a)
     | InvalidToMapType (Expr s a)
     | MapTypeMismatch (Expr s a) (Expr s a)
@@ -918,6 +866,10 @@
     | MissingField Text (Expr s a)
     | MissingConstructor Text (Expr s a)
     | ProjectionTypeMismatch Text (Expr s a) (Expr s a) (Expr s a) (Expr s a)
+    | AssertionFailed (Expr s a) (Expr s a)
+    | NotAnEquivalence (Expr s a)
+    | IncomparableExpression (Expr s a)
+    | EquivalenceTypeMismatch (Expr s a) (Expr s a) (Expr s a) (Expr s a)
     | CantAnd (Expr s a) (Expr s a)
     | CantOr (Expr s a) (Expr s a)
     | CantEQ (Expr s a) (Expr s a)
@@ -927,7 +879,6 @@
     | CantListAppend (Expr s a) (Expr s a)
     | CantAdd (Expr s a) (Expr s a)
     | CantMultiply (Expr s a) (Expr s a)
-    | NoDependentTypes (Expr s a) (Expr s a)
     deriving (Show)
 
 shortTypeMessage :: (Eq a, Pretty a, ToTerm a) => TypeMessage s a -> Doc Ann
@@ -1364,7 +1315,7 @@
   where
     short = "Wrong type of function argument\n"
         <>  "\n"
-        <>  Dhall.Diff.diffNormalized expr1 expr3
+        <>  Dhall.Diff.doc (Dhall.Diff.diffNormalized expr1 expr3)
 
     long =
         "Explanation: Every function declares what type or kind of argument to accept    \n\
@@ -1498,7 +1449,7 @@
   where
     short = "Expression doesn't match annotation\n"
         <>  "\n"
-        <>  Dhall.Diff.diffNormalized expr1 expr2
+        <>  Dhall.Diff.doc (Dhall.Diff.diffNormalized expr1 expr2)
     long =
         "Explanation: You can annotate an expression with its type or kind using the     \n\
         \❰:❱ symbol, like this:                                                          \n\
@@ -1781,7 +1732,7 @@
   where
     short = "❰if❱ branches must have matching types\n"
         <>  "\n"
-        <>  Dhall.Diff.diffNormalized expr1 expr3
+        <>  Dhall.Diff.doc (Dhall.Diff.diffNormalized expr1 expr3)
 
     long =
         "Explanation: Every ❰if❱ expression has a ❰then❱ and ❰else❱ branch, each of which\n\
@@ -1944,7 +1895,7 @@
   where
     short = "List elements should all have the same type\n"
         <>  "\n"
-        <>  Dhall.Diff.diffNormalized expr0 expr2
+        <>  Dhall.Diff.doc (Dhall.Diff.diffNormalized expr0 expr2)
 
     long =
         "Explanation: Every element in a list must have the same type                    \n\
@@ -1982,7 +1933,7 @@
   where
     short = "List element has the wrong type\n"
         <>  "\n"
-        <>  Dhall.Diff.diffNormalized expr0 expr2
+        <>  Dhall.Diff.doc (Dhall.Diff.diffNormalized expr0 expr2)
 
     long =
         "Explanation: Every element in the list must have a type matching the type       \n\
@@ -2101,122 +2052,6 @@
         txt0 = insert k
         txt1 = insert expr0
 
-prettyTypeMessage (FieldAnnotationMismatch k0 expr0 c0 k1 expr1 c1) = ErrorMessages {..}
-  where
-    short = "Field annotation mismatch"
-
-    long =
-        "Explanation: Every record type annotates each field with a ❰Type❱ or a ❰Kind❱,  \n\
-        \like this:                                                                      \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \    ┌──────────────────────────────────────────────┐                            \n\
-        \    │ { foo : Natural, bar : Integer, baz : Text } │  Every field is annotated  \n\
-        \    └──────────────────────────────────────────────┘  with a ❰Type❱             \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \    ┌────────────────────────────┐                                              \n\
-        \    │ { foo : Type, bar : Type } │  Every field is annotated                    \n\
-        \    └────────────────────────────┘  with a ❰Kind❱                               \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \However, you cannot have a record type with both a ❰Type❱ and ❰Kind❱ annotation:\n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \              This is a ❰Type❱ annotation                                       \n\
-        \              ⇩                                                                 \n\
-        \    ┌───────────────────────────────┐                                           \n\
-        \    │ { foo : Natural, bar : Type } │  Invalid record type                      \n\
-        \    └───────────────────────────────┘                                           \n\
-        \                             ⇧                                                  \n\
-        \                             ... but this is a ❰Kind❱ annotation                \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \You provided a record type with a field named:                                  \n\
-        \                                                                                \n\
-        \" <> txt0 <> "\n\
-        \                                                                                \n\
-        \... annotated with the following expression:                                    \n\
-        \                                                                                \n\
-        \" <> txt1 <> "\n\
-        \                                                                                \n\
-        \... which is a " <> level c1 <> " whereas another field named:                  \n\
-        \                                                                                \n\
-        \" <> txt2 <> "\n\
-        \                                                                                \n\
-        \... annotated with the following expression:                                    \n\
-        \                                                                                \n\
-        \" <> txt3 <> "\n\
-        \                                                                                \n\
-        \... is a " <> level c0 <> ", which does not match                               \n"
-      where
-        txt0 = insert k0
-        txt1 = insert expr0
-        txt2 = insert k1
-        txt3 = insert expr1
-
-        level Type = "❰Type❱"
-        level Kind = "❰Kind❱"
-        level Sort = "❰Sort❱"
-
-prettyTypeMessage (FieldMismatch k0 expr0 c0 k1 expr1 c1) = ErrorMessages {..}
-  where
-    short = "Field mismatch"
-
-    long =
-        "Explanation: Every record has fields that can be either terms or types, like    \n\
-        \this:                                                                           \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \    ┌──────────────────────────────────────┐                                    \n\
-        \    │ { foo = 1, bar = True, baz = \"ABC\" } │  Every field is a term           \n\
-        \    └──────────────────────────────────────┘                                    \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \    ┌───────────────────────────────┐                                           \n\
-        \    │ { foo = Natural, bar = Text } │  Every field is a type                    \n\
-        \    └───────────────────────────────┘                                           \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \However, you cannot have a record that stores both terms and types:             \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \              This is a term                                                    \n\
-        \              ⇩                                                                 \n\
-        \    ┌─────────────────────────┐                                                 \n\
-        \    │ { foo = 1, bar = Bool } │  Invalid record                                 \n\
-        \    └─────────────────────────┘                                                 \n\
-        \                       ⇧                                                        \n\
-        \                       ... but this is a type                                   \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \You provided a record with a field named:                                       \n\
-        \                                                                                \n\
-        \" <> txt0 <> "\n\
-        \                                                                                \n\
-        \... whose value was:                                                            \n\
-        \                                                                                \n\
-        \" <> txt1 <> "\n\
-        \                                                                                \n\
-        \... which is a " <> level c1 <> " whereas another field named:                  \n\
-        \                                                                                \n\
-        \" <> txt2 <> "\n\
-        \                                                                                \n\
-        \... whose value was:                                                            \n\
-        \                                                                                \n\
-        \" <> txt3 <> "\n\
-        \                                                                                \n\
-        \... is a " <> level c0 <> ", which does not match                               \n"
-      where
-        txt0 = insert k0
-        txt1 = insert expr0
-        txt2 = insert k1
-        txt3 = insert expr1
-
-        level Type = "term"
-        level Kind = "type"
-        level Sort = "kind"
-
 prettyTypeMessage (InvalidAlternativeType k expr0) = ErrorMessages {..}
   where
     short = "Invalid alternative type"
@@ -2272,48 +2107,6 @@
         txt0 = insert k
         txt1 = insert expr0
 
-prettyTypeMessage (InvalidAlternative k expr0) = ErrorMessages {..}
-  where
-    short = "Invalid alternative"
-
-    long =
-        "Explanation: Every union literal begins by selecting one alternative and        \n\
-        \specifying the value for that alternative, like this:                           \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \        Select the ❰Left❱ alternative, whose value is ❰True❱                    \n\
-        \        ⇩                                                                       \n\
-        \    ┌──────────────────────────────────┐                                        \n\
-        \    │ < Left = True, Right : Natural > │  A union literal with two alternatives \n\
-        \    └──────────────────────────────────┘                                        \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \However, this value must be a term, type, or kind.  For example, the following  \n\
-        \values are " <> _NOT <> " valid:                                                \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \    ┌─────────────────┐                                                         \n\
-        \    │ < Left = Sort > │  Invalid union literal                                  \n\
-        \    └─────────────────┘                                                         \n\
-        \               ⇧                                                                \n\
-        \               This is not a term, type, or kind                                \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \────────────────────────────────────────────────────────────────────────────────\n\
-        \                                                                                \n\
-        \You provided a union literal with an alternative named:                         \n\
-        \                                                                                \n\
-        \" <> txt0 <> "\n\
-        \                                                                                \n\
-        \... whose value is:                                                             \n\
-        \                                                                                \n\
-        \" <> txt1 <> "\n\
-        \                                                                                \n\
-        \... which is not a term, type, or kind.                                         \n"
-      where
-        txt0 = insert k
-        txt1 = insert expr0
-
 prettyTypeMessage (AlternativeAnnotationMismatch k0 expr0 c0 k1 expr1 c1) = ErrorMessages {..}
   where
     short = "Alternative annotation mismatch"
@@ -2382,7 +2175,7 @@
   where
     short = "You can only append ❰List❱s with matching element types\n"
         <>  "\n"
-        <>  Dhall.Diff.diffNormalized expr0 expr1
+        <>  Dhall.Diff.doc (Dhall.Diff.diffNormalized expr0 expr1)
 
     long =
         "Explanation: You can append two ❰List❱s using the ❰#❱ operator, like this:      \n\
@@ -2421,32 +2214,6 @@
         txt0 = insert expr0
         txt1 = insert expr1
 
-prettyTypeMessage (DuplicateAlternative k) = ErrorMessages {..}
-  where
-    short = "Duplicate union alternative"
-
-    long =
-        "Explanation: Unions may not have two alternatives that share the same name      \n\
-        \                                                                                \n\
-        \For example, the following expressions are " <> _NOT <> " valid:                \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \    ┌─────────────────────────────┐                                             \n\
-        \    │ < foo = True | foo : Text > │  Invalid: ❰foo❱ appears twice               \n\
-        \    └─────────────────────────────┘                                             \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \    ┌───────────────────────────────────────┐                                   \n\
-        \    │ < foo = 1 | bar : Bool | bar : Text > │  Invalid: ❰bar❱ appears twice     \n\
-        \    └───────────────────────────────────────┘                                   \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \You have more than one alternative named:                                       \n\
-        \                                                                                \n\
-        \" <> txt0 <> "\n"
-      where
-        txt0 = insert k
-
 prettyTypeMessage (MustCombineARecord c expr0 expr1) = ErrorMessages {..}
   where
     short = "You can only combine records"
@@ -2485,10 +2252,10 @@
         \                                                                                \n\
         \                                                                                \n\
         \    ┌───────────────────────────────────────────┐                               \n\
-        \    │ { foo = 1, bar = \"ABC\" } " <> op <> " < baz = True > │                  \n\
+        \    │ { foo = 1, bar = \"ABC\" } " <> op <> " < baz : Bool > │                  \n\
         \    └───────────────────────────────────────────┘                               \n\
         \                                 ⇧                                              \n\
-        \                                 Invalid: This is a union and not a record      \n\
+        \                                 Invalid: This is a union type and not a record \n\
         \                                                                                \n\
         \                                                                                \n\
         \You tried to combine the following value:                                       \n\
@@ -2503,62 +2270,6 @@
         txt0 = insert expr0
         txt1 = insert expr1
 
-prettyTypeMessage (RecordMismatch c expr0 expr1 const0 const1) = ErrorMessages {..}
-  where
-    short = "Record mismatch"
-
-    long =
-        "Explanation: You can only use the ❰" <> op <> "❱ operator to combine records if they both  \n\
-        \store terms or both store types.                                                \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \    ┌──────────────────────────────┐                                            \n\
-        \    │ { foo = 1 } " <> op <> " { baz = True } │  Valid: Both records store terms           \n\
-        \    └──────────────────────────────┘                                            \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \    ┌─────────────────────────────────┐                                         \n\
-        \    │ { foo = Bool } " <> op <> " { bar = Text } │  Valid: Both records store types        \n\
-        \    └─────────────────────────────────┘                                         \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \... but you cannot combine two records if one of the records stores types and   \n\
-        \the other record stores terms.                                                  \n\
-        \                                                                                \n\
-        \For example, the following expression is " <> _NOT <> " valid:                  \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \      Record of terms                                                           \n\
-        \      ⇩                                                                         \n\
-        \    ┌──────────────────────────────┐                                            \n\
-        \    │ { foo = 1 } " <> op <> " { bar = Text } │  Invalid: Mixing terms and types           \n\
-        \    └──────────────────────────────┘                                            \n\
-        \                               ⇧                                                \n\
-        \                               Record of types                                  \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \You tried to combine the following record:                                      \n\
-        \                                                                                \n\
-        \" <> txt0 <> "\n\
-        \                                                                                \n\
-        \... which stores " <> class0 <> ", with the following record:                   \n\
-        \                                                                                \n\
-        \" <> txt1 <> "\n\
-        \                                                                                \n\
-        \... which stores " <> class1 <> ".                                              \n"
-      where
-        op   = pretty c
-
-        txt0 = insert expr0
-        txt1 = insert expr1
-
-        toClass Type = "terms"
-        toClass Kind = "types"
-        toClass Sort = "kinds"
-
-        class0 = toClass const0
-        class1 = toClass const1
-
 prettyTypeMessage (CombineTypesRequiresRecordType expr0 expr1) =
     ErrorMessages {..}
   where
@@ -2736,7 +2447,7 @@
         \                                                                                \n\
         \                                                                                \n\
         \    ┌─────────────────────────────────────────────────────────────────────┐     \n\
-        \    │     let union    = < Left = 2 | Right : Bool >                      │     \n\
+        \    │     let union    = < Left : Natural | Right : Bool >.Left 2         │     \n\
         \    │ in  let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │     \n\
         \    │ in  merge handlers union : Bool                                     │     \n\
         \    └─────────────────────────────────────────────────────────────────────┘     \n\
@@ -2747,10 +2458,10 @@
         \For example, the following expression is " <> _NOT <> " valid:                  \n\
         \                                                                                \n\
         \                                                                                \n\
-        \    ┌─────────────────────────────────────────┐                                 \n\
-        \    │ let handler = λ(x : Bool) → x           │                                 \n\
-        \    │ in  merge handler < Foo = True > : True │                                 \n\
-        \    └─────────────────────────────────────────┘                                 \n\
+        \    ┌────────────────────────────────────────────────────┐                      \n\
+        \    │ let handler = λ(x : Bool) → x                      │                      \n\
+        \    │ in  merge handler (< Foo : Bool >.Foo True) : Bool │                      \n\
+        \    └────────────────────────────────────────────────────┘                      \n\
         \                ⇧                                                               \n\
         \                Invalid: ❰handler❱ isn't a record                               \n\
         \                                                                                \n\
@@ -2790,11 +2501,11 @@
         \handler per alternative, like this:                                             \n\
         \                                                                                \n\
         \                                                                                \n\
-        \    ┌─────────────────────────────────────────────────────────────────────┐     \n\
-        \    │     let union    = < Left = 2 | Right : Bool >                      │     \n\
-        \    │ in  let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │     \n\
-        \    │ in  merge handlers union : Bool                                     │     \n\
-        \    └─────────────────────────────────────────────────────────────────────┘     \n\
+        \    ┌─────────────────────────────────────────────────────────────────┐         \n\
+        \    │ let union    = < Left : Natural | Right : Bool >.Left 2         │         \n\
+        \    │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │         \n\
+        \    │ in  merge handlers union : Bool                                 │         \n\
+        \    └─────────────────────────────────────────────────────────────────┘         \n\
         \                                                                                \n\
         \                                                                                \n\
         \... but the second argument to ❰merge❱ must be a union and not some other type. \n\
@@ -2830,11 +2541,11 @@
         \handler per alternative, like this:                                             \n\
         \                                                                                \n\
         \                                                                                \n\
-        \    ┌─────────────────────────────────────────────────────────────────────┐     \n\
-        \    │     let union    = < Left = 2 | Right : Bool >                      │     \n\
-        \    │ in  let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │     \n\
-        \    │ in  merge handlers union : Bool                                     │     \n\
-        \    └─────────────────────────────────────────────────────────────────────┘     \n\
+        \    ┌─────────────────────────────────────────────────────────────────┐         \n\
+        \    │ let union    = < Left : Natural | Right : Bool >.Left 2         │         \n\
+        \    │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │         \n\
+        \    │ in  merge handlers union : Bool                                 │         \n\
+        \    └─────────────────────────────────────────────────────────────────┘         \n\
         \                                                                                \n\
         \                                                                                \n\
         \... but you must provide exactly one handler per alternative in the union.  You \n\
@@ -2843,14 +2554,14 @@
         \For example, the following expression is " <> _NOT <> " valid:                  \n\
         \                                                                                \n\
         \                                                                                \n\
-        \    ┌───────────────────────────────────────┐                                   \n\
-        \    │     let union    = < Left = 2 >       │  The ❰Right❱ alternative is       \n\
-        \    │ in  let handlers =                    │  missing                          \n\
-        \    │             { Left  = Natural/even    │                                   \n\
-        \    │             , Right = λ(x : Bool) → x │  Invalid: ❰Right❱ handler isn't   \n\
-        \    │             }                         │           used                    \n\
-        \    │ in  merge handlers union : Bool       │                                   \n\
-        \    └───────────────────────────────────────┘                                   \n\
+        \    ┌──────────────────────────────────────────┐                                \n\
+        \    │ let union    = < Left : Natural >.Left 2 │  The ❰Right❱ alternative is    \n\
+        \    │ let handlers =                           │  missing                       \n\
+        \    │             { Left  = Natural/even       │                                \n\
+        \    │             , Right = λ(x : Bool) → x    │  Invalid: ❰Right❱ handler isn't\n\
+        \    │             }                            │           used                 \n\
+        \    │ in  merge handlers union : Bool          │                                \n\
+        \    └──────────────────────────────────────────┘                                \n\
         \                                                                                \n\
         \                                                                                \n\
         \You provided the following handlers:                                            \n\
@@ -2870,11 +2581,11 @@
         \handler per alternative, like this:                                             \n\
         \                                                                                \n\
         \                                                                                \n\
-        \    ┌─────────────────────────────────────────────────────────────────────┐     \n\
-        \    │     let union    = < Left = 2 | Right : Bool >                      │     \n\
-        \    │ in  let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │     \n\
-        \    │ in  merge handlers union : Bool                                     │     \n\
-        \    └─────────────────────────────────────────────────────────────────────┘     \n\
+        \    ┌─────────────────────────────────────────────────────────────────┐         \n\
+        \    │ let union    = < Left : Natural | Right : Bool >.Left 2         │         \n\
+        \    │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │         \n\
+        \    │ in  merge handlers union : Bool                                 │         \n\
+        \    └─────────────────────────────────────────────────────────────────┘         \n\
         \                                                                                \n\
         \                                                                                \n\
         \... but you must provide exactly one handler per alternative in the union.  You \n\
@@ -2883,13 +2594,13 @@
         \For example, the following expression is " <> _NOT <> " valid:                  \n\
         \                                                                                \n\
         \                                                                                \n\
-        \                                              Invalid: Missing ❰Right❱ handler  \n\
-        \                                              ⇩                                 \n\
-        \    ┌─────────────────────────────────────────────────┐                         \n\
-        \    │     let handlers = { Left = Natural/even }      │                         \n\
-        \    │ in  let union    = < Left = 2 | Right : Bool >  │                         \n\
-        \    │ in  merge handlers union : Bool                 │                         \n\
-        \    └─────────────────────────────────────────────────┘                         \n\
+        \                                          Invalid: Missing ❰Right❱ handler      \n\
+        \                                          ⇩                                     \n\
+        \    ┌──────────────────────────────────────────────────────────────┐            \n\
+        \    │ let handlers = { Left = Natural/even }                       │            \n\
+        \    │ let union    = < Left : Natural | Right : Bool >.Left 2      │            \n\
+        \    │ in  merge handlers union : Bool                              │            \n\
+        \    └──────────────────────────────────────────────────────────────┘            \n\
         \                                                                                \n\
         \                                                                                \n\
         \Note that you need to provide handlers for other alternatives even if those     \n\
@@ -2911,11 +2622,11 @@
         \least one alternative, like this                                                \n\
         \                                                                                \n\
         \                                                                                \n\
-        \    ┌─────────────────────────────────────────────────────────────────────┐     \n\
-        \    │     let union    = < Left = 2 | Right : Bool >                      │     \n\
-        \    │ in  let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │     \n\
-        \    │ in  merge handlers union                                            │     \n\
-        \    └─────────────────────────────────────────────────────────────────────┘     \n\
+        \    ┌─────────────────────────────────────────────────────────────────┐         \n\
+        \    │ let union    = < Left : Natural | Right : Bool >.Left 2         │         \n\
+        \    │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │         \n\
+        \    │ in  merge handlers union : Bool                                 │         \n\
+        \    └─────────────────────────────────────────────────────────────────┘         \n\
         \                                                                                \n\
         \                                                                                \n\
         \However, you must provide a type annotation when merging an empty union:        \n\
@@ -2936,18 +2647,18 @@
   where
     short = "Wrong handler input type\n"
         <>  "\n"
-        <>  Dhall.Diff.diffNormalized expr1 expr2
+        <>  Dhall.Diff.doc (Dhall.Diff.diffNormalized expr1 expr2)
 
     long =
         "Explanation: You can ❰merge❱ the alternatives of a union using a record with one\n\
         \handler per alternative, like this:                                             \n\
         \                                                                                \n\
         \                                                                                \n\
-        \    ┌─────────────────────────────────────────────────────────────────────┐     \n\
-        \    │     let union    = < Left = 2 | Right : Bool >                      │     \n\
-        \    │ in  let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │     \n\
-        \    │ in  merge handlers union : Bool                                     │     \n\
-        \    └─────────────────────────────────────────────────────────────────────┘     \n\
+        \    ┌─────────────────────────────────────────────────────────────────┐         \n\
+        \    │ let union    = < Left : Natural | Right : Bool >.Left 2         │         \n\
+        \    │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │         \n\
+        \    │ in  merge handlers union : Bool                                 │         \n\
+        \    └─────────────────────────────────────────────────────────────────┘         \n\
         \                                                                                \n\
         \                                                                                \n\
         \... as long as the input type of each handler function matches the type of the  \n\
@@ -2970,11 +2681,11 @@
         \                                                                                \n\
         \      Invalid: Doesn't match the type of the ❰Right❱ alternative                \n\
         \                                                               ⇩                \n\
-        \    ┌──────────────────────────────────────────────────────────────────────┐    \n\
-        \    │     let handlers = { Left = Natural/even | Right = λ(x : Text) → x } │    \n\
-        \    │ in  let union    = < Left = 2 | Right : Bool >                       │    \n\
-        \    │ in  merge handlers union : Bool                                      │    \n\
-        \    └──────────────────────────────────────────────────────────────────────┘    \n\
+        \    ┌──────────────────────────────────────────────────────────────────┐        \n\
+        \    │ let handlers = { Left = Natural/even | Right = λ(x : Text) → x } │        \n\
+        \    │ let union    = < Left : Natural | Right : Bool >.Left 2          │        \n\
+        \    │ in  merge handlers union : Bool                                  │        \n\
+        \    └──────────────────────────────────────────────────────────────────┘        \n\
         \                                                                                \n\
         \                                                                                \n\
         \Your handler for the following alternative:                                     \n\
@@ -2998,18 +2709,18 @@
   where
     short = "Wrong handler output type\n"
         <>  "\n"
-        <>  Dhall.Diff.diffNormalized expr1 expr2
+        <>  Dhall.Diff.doc (Dhall.Diff.diffNormalized expr1 expr2)
 
     long =
         "Explanation: You can ❰merge❱ the alternatives of a union using a record with one\n\
         \handler per alternative, like this:                                             \n\
         \                                                                                \n\
         \                                                                                \n\
-        \    ┌─────────────────────────────────────────────────────────────────────┐     \n\
-        \    │     let union    = < Left = 2 | Right : Bool >                      │     \n\
-        \    │ in  let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │     \n\
-        \    │ in  merge handlers union : Bool                                     │     \n\
-        \    └─────────────────────────────────────────────────────────────────────┘     \n\
+        \    ┌─────────────────────────────────────────────────────────────────┐         \n\
+        \    │ let union    = < Left : Natural | Right : Bool >.Left 2         │         \n\
+        \    │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │         \n\
+        \    │ in  merge handlers union : Bool                                 │         \n\
+        \    └─────────────────────────────────────────────────────────────────┘         \n\
         \                                                                                \n\
         \                                                                                \n\
         \... as long as the output type of each handler function matches the declared    \n\
@@ -3032,11 +2743,11 @@
         \For example, the following expression is " <> _NOT <> " valid:                  \n\
         \                                                                                \n\
         \                                                                                \n\
-        \    ┌──────────────────────────────────────────────────────────────────────┐    \n\
-        \    │     let union    = < Left = 2 | Right : Bool >                       │    \n\
-        \    │ in  let handlers = { Left = Natural/even, Right = λ(x : Bool) → x }  │    \n\
-        \    │ in  merge handlers union : Text                                      │    \n\
-        \    └──────────────────────────────────────────────────────────────────────┘    \n\
+        \    ┌──────────────────────────────────────────────────────────────────┐        \n\
+        \    │ let union    = < Left : Natural | Right : Bool >.Left 2          │        \n\
+        \    │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x }  │        \n\
+        \    │ in  merge handlers union : Text                                  │        \n\
+        \    └──────────────────────────────────────────────────────────────────┘        \n\
         \                                 ⇧                                              \n\
         \                                 Invalid: Doesn't match output of either handler\n\
         \                                                                                \n\
@@ -3062,18 +2773,18 @@
   where
     short = "Handlers should have the same output type\n"
         <>  "\n"
-        <>  Dhall.Diff.diffNormalized expr0 expr1
+        <>  Dhall.Diff.doc (Dhall.Diff.diffNormalized expr0 expr1)
 
     long =
         "Explanation: You can ❰merge❱ the alternatives of a union using a record with one\n\
         \handler per alternative, like this:                                             \n\
         \                                                                                \n\
         \                                                                                \n\
-        \    ┌─────────────────────────────────────────────────────────────────────┐     \n\
-        \    │     let union    = < Left = 2 | Right : Bool >                      │     \n\
-        \    │ in  let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │     \n\
-        \    │ in  merge handlers union                                            │     \n\
-        \    └─────────────────────────────────────────────────────────────────────┘     \n\
+        \    ┌─────────────────────────────────────────────────────────────────┐         \n\
+        \    │ let union    = < Left : Natural | Right : Bool >.Left 2         │         \n\
+        \    │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │         \n\
+        \    │ in  merge handlers union : Bool                                 │         \n\
+        \    └─────────────────────────────────────────────────────────────────┘         \n\
         \                                                                                \n\
         \                                                                                \n\
         \... as long as the output type of each handler function is the same:            \n\
@@ -3090,12 +2801,12 @@
         \                                                                                \n\
         \                                                                                \n\
         \    ┌─────────────────────────────────────────────────┐                         \n\
-        \    │     let union    = < Left = 2 | Right : Bool >  │                         \n\
-        \    │ in  let handlers =                              │                         \n\
+        \    │ let Union = < Left : Natural | Right : Bool >   │                         \n\
+        \    │ let handlers =                                  │                         \n\
         \    │              { Left  = λ(x : Natural) → x       │  This outputs ❰Natural❱ \n\
         \    │              , Right = λ(x : Bool   ) → x       │  This outputs ❰Bool❱    \n\
         \    │              }                                  │                         \n\
-        \    │ in  merge handlers union                        │                         \n\
+        \    │ in  merge handlers (Union.Left 2)               │                         \n\
         \    └─────────────────────────────────────────────────┘                         \n\
         \                ⇧                                                               \n\
         \                Invalid: The handlers in this record don't have matching outputs\n\
@@ -3123,21 +2834,21 @@
         \handler per alternative, like this:                                             \n\
         \                                                                                \n\
         \                                                                                \n\
-        \    ┌─────────────────────────────────────────────────────────────────────┐     \n\
-        \    │     let union    = < Left = 2 | Right : Bool >                      │     \n\
-        \    │ in  let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │     \n\
-        \    │ in  merge handlers union : Bool                                     │     \n\
-        \    └─────────────────────────────────────────────────────────────────────┘     \n\
+        \    ┌─────────────────────────────────────────────────────────────────┐         \n\
+        \    │ let union    = < Left : Natural | Right : Bool >.Left 2         │         \n\
+        \    │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │         \n\
+        \    │ in  merge handlers union : Bool                                 │         \n\
+        \    └─────────────────────────────────────────────────────────────────┘         \n\
         \                                                                                \n\
         \                                                                                \n\
-        \... as long as each handler is a function                                       \n\
+        \... as long as each handler is a function -- FIXME                              \n\
         \                                                                                \n\
         \For example, the following expression is " <> _NOT <> " valid:                  \n\
         \                                                                                \n\
         \                                                                                \n\
-        \    ┌─────────────────────────────────────────┐                                 \n\
-        \    │ merge { Foo = True } < Foo = 1 > : Bool │                                 \n\
-        \    └─────────────────────────────────────────┘                                 \n\
+        \    ┌───────────────────────────────────────────────────────┐                   \n\
+        \    │ merge { Foo = True } (< Foo : Natural >.Foo 1) : Bool │                   \n\
+        \    └───────────────────────────────────────────────────────┘                   \n\
         \                    ⇧                                                           \n\
         \                    Invalid: Not a function                                     \n\
         \                                                                                \n\
@@ -3164,13 +2875,39 @@
         \                                                                                \n\
         \                                                                                \n\
         \    ┌─────────────────────────────────────────────────────────────────────┐     \n\
-        \    │     let record = { one = 1, two = 2 }                               │     \n\
+        \    │ let record = { one = 1, two = 2 }                                   │     \n\
         \    │ in  toMap record : List { mapKey : Text, mapValue : Natural}        │     \n\
         \    └─────────────────────────────────────────────────────────────────────┘     \n\
         \                                                                                \n\
         \                                                                                \n\
         \... but the argument to ❰toMap❱ must be a record and not some other type.       \n"
 
+prettyTypeMessage (InvalidToMapRecordKind type_ kind) = ErrorMessages {..}
+  where
+    short = "❰toMap❱ expects a record of kind ❰Type❱"
+
+    long =
+        "Explanation: You can apply ❰toMap❱ to any homogenous record of kind ❰Type❱, like\n\
+        \ this:                                                                          \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌─────────────────────────────────────────────────────────────────────┐     \n\
+        \    │ let record = { one = 1, two = 2 }                                   │     \n\
+        \    │ in  toMap record : List { mapKey : Text, mapValue : Natural}        │     \n\
+        \    └─────────────────────────────────────────────────────────────────────┘     \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \... but records of kind ❰Kind❱ or ❰Sort❱ cannot be turned into ❰List❱s.         \n\
+        \────────────────────────────────────────────────────────────────────────────────\n\
+        \                                                                                \n\
+        \You applied ❰toMap❱ to a record of the following type:                          \n\
+        \                                                                                \n\
+        \" <> insert type_ <> "\n\
+        \                                                                                \n\
+        \... which has kind                                                              \n\
+        \                                                                                \n\
+        \" <> insert kind <> "\n"
+
 prettyTypeMessage (HeterogenousRecordToMap _expr0 _expr1 _expr2) = ErrorMessages {..}
   where
     short = "❰toMap❱ expects a homogenous record"
@@ -3180,7 +2917,7 @@
         \                                                                                \n\
         \                                                                                \n\
         \    ┌─────────────────────────────────────────────────────────────────────┐     \n\
-        \    │     let record = { one = 1, two = 2 }                               │     \n\
+        \    │ let record = { one = 1, two = 2 }                                   │     \n\
         \    │ in  toMap record : List { mapKey : Text, mapValue : Natural}        │     \n\
         \    └─────────────────────────────────────────────────────────────────────┘     \n\
         \                                                                                \n\
@@ -3200,7 +2937,7 @@
   where
     short = "❰toMap❱ result type doesn't match annotation"
         <>  "\n"
-        <>  Dhall.Diff.diffNormalized expr0 expr1
+        <>  Dhall.Diff.doc (Dhall.Diff.diffNormalized expr0 expr1)
 
     long =
         "Explanation: a ❰toMap❱ application has been annotated with a type that doesn't  \n\
@@ -3236,7 +2973,7 @@
         \                                                                                \n\
         \                                                                                \n\
         \    ┌─────────────────────────────────────────────────────────────────────┐     \n\
-        \    │     let record = { one = 1, two = 2 }                               │     \n\
+        \    │ let record = { one = 1, two = 2 }                                   │     \n\
         \    │ in  toMap record                                                    │     \n\
         \    └─────────────────────────────────────────────────────────────────────┘     \n\
         \                                                                                \n\
@@ -3511,7 +3248,7 @@
   where
     short = "Projection type mismatch\n"
         <>  "\n"
-        <>  Dhall.Diff.diffNormalized expr2 expr3
+        <>  Dhall.Diff.doc (Dhall.Diff.diffNormalized expr2 expr3)
 
     long =
         "Explanation: You can project a subset of fields from a record by specifying the \n\
@@ -3554,6 +3291,194 @@
         txt1 = insert expr0
         txt2 = insert expr1
 
+prettyTypeMessage (AssertionFailed expr0 expr1) = ErrorMessages {..}
+  where
+    short = "Assertion failed\n"
+        <>  "\n"
+        <>  Dhall.Diff.doc (Dhall.Diff.diffNormalized expr0 expr1)
+
+    long =
+        "Explanation: You can assert at type-checking time that two terms are equal if   \n\
+        \they have the same normal form, like this:                                      \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌────────────────────┐                                                      \n\
+        \    │ assert : 2 + 2 ≡ 4 │  This is valid                                       \n\
+        \    └────────────────────┘                                                      \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \... and an assertion still succeeds if the normal forms only differ by renaming \n\
+        \bound variables, like this:                                                     \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌──────────────────────────────────────────────────────┐                    \n\
+        \    │ assert : λ(n : Natural) → n + 0 ≡ λ(m : Natural) → m │  This is also valid\n\
+        \    └──────────────────────────────────────────────────────┘                    \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \However, an assertion fails if the normal forms differ in any other way.  For   \n\
+        \example, the following assertion is " <> _NOT <> " valid:                       \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌────────────────┐                                                          \n\
+        \    │ assert : 0 ≡ 1 │  Invalid: ❰0❱ does not equal ❰1❱                         \n\
+        \    └────────────────┘                                                          \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \Some common reasons why you might get this error:                               \n\
+        \                                                                                \n\
+        \● You might have tried to ❰assert❱ a precondition on a function's input, like   \n\
+        \  this:                                                                         \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌──────────────────────────────────────────────────────────────────┐        \n\
+        \    │ λ(n : Natural) → let _ = assert : Natural/isZero n ≡ False in n  │        \n\
+        \    └──────────────────────────────────────────────────────────────────┘        \n\
+        \                                        ⇧                                       \n\
+        \                                        Invalid: This assertion will always fail\n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \  This will not work.  Such an assertion is checking all possible inputs to the \n\
+        \  function, before you've even used the function at all.                        \n\
+        \                                                                                \n\
+        \────────────────────────────────────────────────────────────────────────────────\n\
+        \                                                                                \n\
+        \You tried to assert that this expression:                                       \n\
+        \                                                                                \n\
+        \" <> txt0 <> "\n\
+        \                                                                                \n\
+        \... is the same as this other expression:                                       \n\
+        \                                                                                \n\
+        \" <> txt1 <> "\n\
+        \                                                                                \n\
+        \... but they differ\n"
+      where
+        txt0 = insert expr0
+        txt1 = insert expr1
+
+prettyTypeMessage (NotAnEquivalence expr) = ErrorMessages {..}
+  where
+    short = "Not an equivalence\n"
+
+    long =
+        "Explanation: The type annotation for an ❰assert❱ must evaluate to an equivalence\n\
+        \of the form ❰x ≡ y❱, like this:                                                 \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌────────────────────┐                                                      \n\
+        \    │ assert : 2 + 2 ≡ 4 │  This is valid                                       \n\
+        \    └────────────────────┘                                                      \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \... but any other type is not a valid annotation.  For example, the following   \n\
+        \assertion is " <> _NOT <> " valid:                                              \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌───────────────┐                                                           \n\
+        \    │ assert : True │  Invalid: ❰True❱ is not an equivalence                    \n\
+        \    └───────────────┘                                                           \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \Some common reasons why you might get this error:                               \n\
+        \                                                                                \n\
+        \● You tried to supply an expression of type ❰Bool❱ to the assertion, rather than\n\
+        \  two separate expressions to compare, like this:                               \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌───────────────────────────┐                                               \n\
+        \    │ assert : Natural/isZero 0 │  Invalid: A boolean expression is not the     \n\
+        \    └───────────────────────────┘  same thing as a type-level equivalence       \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \  You have to explicitly compare two expressions, even if that just means       \n\
+        \  comparing the expression to ❰True❱, like this:                                \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌──────────────────────────────────┐                                        \n\
+        \    │ assert : Natural/isZero 0 ≡ True │  Valid: You can assert that two boolean\n\
+        \    └──────────────────────────────────┘  expressions are equivalent            \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \────────────────────────────────────────────────────────────────────────────────\n\
+        \                                                                                \n\
+        \You provided the following type annotation for an ❰assert❱:                     \n\
+        \                                                                                \n\
+        \" <> txt0 <> "\n\
+        \                                                                                \n\
+        \... which is not an equivalence\n"
+      where
+        txt0 = insert expr
+
+prettyTypeMessage (IncomparableExpression expr) = ErrorMessages {..}
+  where
+    short = "Incomparable expression\n"
+
+    long =
+        "Explanation: You can use an ❰assert❱ to compare two terms for equivalence, like \n\
+        \this:                                                                           \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌────────────────────┐                                                      \n\
+        \    │ assert : 2 + 2 ≡ 4 │  This is valid because ❰2 + 2❱ and ❰4❱ are both terms\n\
+        \    └────────────────────┘                                                      \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \... but you cannot compare expressions, that are not terms, such as types.  For \n\
+        \example, the following equivalence is " <> _NOT <> " valid:                     \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌────────────────────────────┐                                              \n\
+        \    │ assert : Natural ≡ Natural │  Invalid: ❰Natural❱ is a type, not a term    \n\
+        \    └────────────────────────────┘                                              \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \You tried to compare the following expression:                                  \n\
+        \                                                                                \n\
+        \" <> txt0 <> "\n\
+        \                                                                                \n\
+        \... which is not a term\n"
+      where
+        txt0 = insert expr
+
+prettyTypeMessage (EquivalenceTypeMismatch l _L r _R) = ErrorMessages {..}
+  where
+    short = "The two sides of the equivalence have different types"
+
+    long =
+        "Explanation: You can use ❰≡❱ to compare two terms of the same type for          \n\
+        \equivalence, like this:                                                         \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌───────────┐                                                               \n\
+        \    │ 2 + 2 ≡ 4 │  This is valid because ❰2 + 2❱ and ❰4❱ have the same type     \n\
+        \    └───────────┘                                                               \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \... but you cannot compare expressions, that have different types.  For example,\n\
+        \the following assertion is " <> _NOT <> " valid:                                \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌──────────┐                                                                \n\
+        \    │ 1 ≡ True │  Invalid: ❰1❱ has type ❰Natural❱, ❰True❱ has type ❰Bool❱       \n\
+        \    └──────────┘                                                                \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \You tried to compare the following expressions:                                 \n\
+        \                                                                                \n\
+        \" <> insert l <> "\n\
+        \                                                                                \n\
+        \... which has type\n\
+        \                                                                                \n\
+        \" <> insert _L <> "\n\
+        \                                                                                \n\
+        \... and\n\
+        \                                                                                \n\
+        \" <> insert r <> "\n\
+        \                                                                                \n\
+        \... which has type\n\
+        \                                                                                \n\
+        \" <> insert _R <> "\n"
+
 prettyTypeMessage (CantAnd expr0 expr1) =
         buildBooleanOperator "&&" expr0 expr1
 
@@ -3707,46 +3632,6 @@
 
 prettyTypeMessage (CantMultiply expr0 expr1) =
         buildNaturalOperator "*" expr0 expr1
-
-prettyTypeMessage (NoDependentTypes expr0 expr1) = ErrorMessages {..}
-  where
-    short = "No dependent types"
-
-    long =
-        "Explanation: The Dhall programming language does not allow functions from terms \n\
-        \to types.  These function types are also known as “dependent function types”    \n\
-        \because you have a type whose value “depends” on the value of a term.           \n\
-        \                                                                                \n\
-        \For example, this is " <> _NOT <> " a legal function type:                      \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \    ┌─────────────┐                                                             \n\
-        \    │ Bool → Type │                                                             \n\
-        \    └─────────────┘                                                             \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \Similarly, this is " <> _NOT <> " legal code:                                   \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \    ┌───────────────────────────────────────────────────┐                       \n\
-        \    │ λ(Vector : Natural → Type → Type) → Vector 0 Text │                       \n\
-        \    └───────────────────────────────────────────────────┘                       \n\
-        \                 ⇧                                                              \n\
-        \                 Invalid dependent type                                         \n\
-        \                                                                                \n\
-        \                                                                                \n\
-        \Your function type is invalid because the input has type:                       \n\
-        \                                                                                \n\
-        \" <> txt0 <> "\n\
-        \                                                                                \n\
-        \... and the output has kind:                                                    \n\
-        \                                                                                \n\
-        \" <> txt1 <> "\n\
-        \                                                                                \n\
-        \... which makes this a forbidden dependent function type                        \n"
-      where
-        txt0 = insert expr0
-        txt1 = insert expr1
 
 buildBooleanOperator :: Pretty a => Text -> Expr s a -> Expr s a -> ErrorMessages
 buildBooleanOperator operator expr0 expr1 = ErrorMessages {..}
diff --git a/src/Dhall/X.hs b/src/Dhall/X.hs
deleted file mode 100644
--- a/src/Dhall/X.hs
+++ /dev/null
@@ -1,28 +0,0 @@
-{-# LANGUAGE RankNTypes #-}
-
-module Dhall.X where
-
-import Data.Data (Data(..))
-import Data.Text.Prettyprint.Doc (Pretty(..))
-import Instances.TH.Lift ()
-import Language.Haskell.TH.Syntax (Lift, lift)
-
--- | Like `Data.Void.Void`, except with a shorter inferred type
-newtype X = X { absurd :: forall a . a }
-
-instance Show X where
-    show = absurd
-
-instance Eq X where
-  _ == _ = True
-
-instance Data X where
-    dataTypeOf = absurd
-    gunfold _ _ _ = undefined
-    toConstr = absurd
-
-instance Pretty X where
-    pretty = absurd
-
-instance Lift X where
-  lift (X impossible) = impossible
diff --git a/tests/Dhall/Test/Dhall.hs b/tests/Dhall/Test/Dhall.hs
--- a/tests/Dhall/Test/Dhall.hs
+++ b/tests/Dhall/Test/Dhall.hs
@@ -1,17 +1,27 @@
 {-# LANGUAGE DeriveAnyClass      #-}
+{-# LANGUAGE DeriveFoldable      #-}
+{-# LANGUAGE DeriveFunctor       #-}
 {-# LANGUAGE DeriveGeneric       #-}
+{-# LANGUAGE DeriveTraversable   #-}
 {-# LANGUAGE FlexibleContexts    #-}
+{-# LANGUAGE OverloadedLists     #-}
 {-# LANGUAGE OverloadedStrings   #-}
 {-# LANGUAGE RecordWildCards     #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE StandaloneDeriving  #-}
+{-# LANGUAGE TemplateHaskell     #-}
+{-# LANGUAGE TypeFamilies        #-}
 
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module Dhall.Test.Dhall where
 
 import Control.Exception (SomeException, try)
+import Data.Fix (Fix(..))
+import Data.Sequence (Seq)
+import Data.Scientific (Scientific)
 import Data.Text (Text)
+import Data.Vector (Vector)
 import Dhall (Inject, Interpret)
 import Dhall.Core (Expr(..))
 import GHC.Generics (Generic)
@@ -19,25 +29,35 @@
 import Test.Tasty
 import Test.Tasty.HUnit
 
+import qualified Data.Text.Lazy
 import qualified Dhall
 import qualified Dhall.Core
 import qualified Dhall.Import
 import qualified Dhall.Map
 import qualified Dhall.Parser
 
+data ExprF expr
+   = LitF Natural
+   | AddF expr expr
+   | MulF expr expr
+   deriving (Eq, Functor, Generic, Interpret, Show)
+
 tests :: TestTree
 tests =
     testGroup "Input"
      [ shouldShowDetailedTypeError
-     , shouldHandleBothUnionLiterals
+     , shouldHandleUnionLiteral
+     , shouldHaveWorkingRecursiveInterpret
      , shouldHaveWorkingGenericAuto
      , shouldHandleUnionsCorrectly
      , shouldTreatAConstructorStoringUnitAsEmptyAlternative
+     , shouldConvertDhallToHaskellCorrectly 
+     , shouldConvertHaskellToDhallCorrectly
      ]
 
 data MyType = MyType { foo :: String , bar :: Natural }
 
-wrongDhallType :: Dhall.Type MyType 
+wrongDhallType :: Dhall.Type MyType
 wrongDhallType = Dhall.Type { .. }
   where expected =
           Dhall.Core.Record
@@ -51,7 +71,7 @@
 shouldShowDetailedTypeError :: TestTree
 shouldShowDetailedTypeError = testCase "detailed TypeError" $ do
   inputEx :: Either SomeException MyType <-
-        try ( Dhall.input wrongDhallType "{  bar = 0, foo = \"foo\" }") 
+        try ( Dhall.input wrongDhallType "{  bar = 0, foo = \"foo\" }")
 
   let expectedMsg =
         "\ESC[1;31mError\ESC[0m: Invalid Dhall.Type                                                  \n\
@@ -69,19 +89,18 @@
         \                                                                                \n"
 
   let assertMsg = "The exception message did not match the expected output"
-  
+
   case inputEx of
     Left ex -> assertEqual assertMsg expectedMsg (show ex)
     Right _ -> fail "The extraction using a wrong type succeded"
 
 -- https://github.com/dhall-lang/dhall-haskell/issues/915
-shouldHandleBothUnionLiterals :: TestTree
-shouldHandleBothUnionLiterals = testCase "Marshal union literals" $ do
+shouldHandleUnionLiteral :: TestTree
+shouldHandleUnionLiteral = testCase "Marshal union literals" $ do
     let example :: Dhall.Type Bool
         example = Dhall.union (Dhall.constructor "Test" Dhall.bool)
 
     _ <- Dhall.input example "< Test : Bool >.Test True"
-    _ <- Dhall.input example "< Test = True >"
 
     return ()
 
@@ -97,6 +116,25 @@
 
     Dhall.embed exampleInputType () @=? Field (Union (Dhall.Map.singleton "A" Nothing)) "A"
 
+shouldHaveWorkingRecursiveInterpret :: TestTree
+shouldHaveWorkingRecursiveInterpret = testGroup "recursive Interpret instance"
+    [ testCase "works for a recursive expression" $ do
+        actual <- Dhall.input Dhall.auto "./tests/recursive/expr0.dhall"
+
+        expected @=? actual
+    , testCase "passes a shadowing sanity check" $ do
+        actual <- Dhall.input Dhall.auto "./tests/recursive/expr1.dhall"
+
+        expected @=? actual
+    ]
+  where
+    expected =
+        Fix
+            (AddF
+                (Fix (MulF (Fix (LitF 3)) (Fix (LitF 7))))
+                (Fix (AddF (Fix (LitF 1)) (Fix (LitF 2))))
+            )
+
 data CompilerFlavor3 =
   GHC3 | GHCJS3 | Helium3
   deriving (Generic, Show, Eq)
@@ -145,13 +183,6 @@
     , "(< N0 : { _1 : Bool } | N1 : { _1 : Natural } | N2 : { _1 : Text } >).N2 { _1 = \"ABC\" }"
         `shouldMarshalInto` N2 "ABC"
 
-    , "< N0 = { _1 = True } | N1 : { _1 : Natural } | N2 : { _1 : Text } >"
-        `shouldMarshalInto` N0 True
-    , "< N0 : { _1 : Bool } | N1 = { _1 = 5 } | N2 : { _1 : Text } >"
-        `shouldMarshalInto` N1 5
-    , "< N0 : { _1 : Bool } | N1 : { _1 : Natural } | N2 = { _1 = \"ABC\" } >"
-        `shouldMarshalInto` N2 "ABC"
-
     , "(< E0 | E1 | E2>).E0" `shouldMarshalInto` E0
     , "(< E0 | E1 | E2>).E1" `shouldMarshalInto` E1
     , "(< E0 | E1 | E2>).E2" `shouldMarshalInto` E2
@@ -163,9 +194,6 @@
     , "(< M0 : { _1 : Bool } | M1 | M2 : { _1 : {} } >).M2 { _1 = {=} }"
         `shouldMarshalInto` M2 ()
 
-    , "< M0 = { _1 = True } | M1 | M2 : { _1 : {} } >"
-        `shouldMarshalInto` M0 True
-
     , N0 True
         `shouldInjectInto`
         "(< N0 : { _1 : Bool } | N1 : { _1 : Natural } | N2 : { _1 : Text } >).N0 { _1 = True }"
@@ -200,3 +228,64 @@
         resolvedExpression <- Dhall.Import.assertNoImports parsedExpression
 
         Dhall.Core.denote resolvedExpression @=? Dhall.embed Dhall.inject value
+
+shouldConvertDhallToHaskellCorrectly :: TestTree
+shouldConvertDhallToHaskellCorrectly =
+    testGroup
+        "Marshall Dhall code to Haskell"
+        [ "True" `correspondsTo` True
+        , "False" `correspondsTo` False
+        , "2" `correspondsTo` (2 :: Natural)
+        , "+2" `correspondsTo` (2 :: Integer)
+        , "2.0" `correspondsTo` (2.0 :: Double)
+        , "2.0" `correspondsTo` (2.0 :: Scientific)
+        , "\"ABC\"" `correspondsTo` ("ABC" :: Data.Text.Text)
+        , "\"ABC\"" `correspondsTo` ("ABC" :: Data.Text.Lazy.Text)
+        , "\"ABC\"" `correspondsTo` ("ABC" :: String)
+        , "Some 2" `correspondsTo` (Just 2 :: Maybe Natural)
+        , "None Natural" `correspondsTo` (Nothing :: Maybe Natural)
+        , "[ 2, 3, 5 ]" `correspondsTo` ([ 2, 3, 5 ] :: Seq Natural)
+        , "[ 2, 3, 5 ]" `correspondsTo` ([ 2, 3, 5 ] :: [Natural])
+        , "[ 2, 3, 5 ]" `correspondsTo` ([ 2, 3, 5 ] :: Vector Natural)
+        , "[] : List Natural" `correspondsTo` ([] :: [Natural])
+        , "{=}" `correspondsTo` ()
+        , "{ _1 = True, _2 = {=} }" `correspondsTo` (True, ())
+        ]
+  where
+    correspondsTo :: (Eq a, Interpret a, Show a) => Text -> a -> TestTree
+    dhallCode `correspondsTo` expectedHaskellValue =
+      testCase "Marshall Dhall code to Haskell" $ do
+          actualHaskellValue <- Dhall.input Dhall.auto dhallCode
+
+          expectedHaskellValue @=? actualHaskellValue
+
+shouldConvertHaskellToDhallCorrectly :: TestTree
+shouldConvertHaskellToDhallCorrectly =
+    testGroup
+        "Marshall Haskell to Dhall code"
+        [ "True" `correspondsTo` True
+        , "False" `correspondsTo` False
+        , "2" `correspondsTo` (2 :: Natural)
+        , "+2" `correspondsTo` (2 :: Integer)
+        , "2.0" `correspondsTo` (2.0 :: Double)
+        , "2.0" `correspondsTo` (2.0 :: Scientific)
+        , "\"ABC\"" `correspondsTo` ("ABC" :: Data.Text.Text)
+        , "\"ABC\"" `correspondsTo` ("ABC" :: Data.Text.Lazy.Text)
+        , "\"ABC\"" `correspondsTo` ("ABC" :: String)
+        , "Some 2" `correspondsTo` (Just 2 :: Maybe Natural)
+        , "None Natural" `correspondsTo` (Nothing :: Maybe Natural)
+        , "[ 2, 3, 5 ]" `correspondsTo` ([ 2, 3, 5 ] :: Seq Natural)
+        , "[ 2, 3, 5 ]" `correspondsTo` ([ 2, 3, 5 ] :: [Natural])
+        , "[ 2, 3, 5 ]" `correspondsTo` ([ 2, 3, 5 ] :: Vector Natural)
+        , "[] : List Natural" `correspondsTo` ([] :: [Natural])
+        , "{=}" `correspondsTo` ()
+        , "{ _1 = True, _2 = {=} }" `correspondsTo` (True, ())
+        ]
+  where
+    correspondsTo :: Inject a => Text -> a -> TestTree
+    expectedDhallCode `correspondsTo` haskellValue =
+        testCase "Marshall Haskell to Dhall code" $ do
+            let actualDhallCode =
+                    Dhall.Core.pretty (Dhall.embed Dhall.inject haskellValue)
+
+            expectedDhallCode @=? actualDhallCode
diff --git a/tests/Dhall/Test/Diff.hs b/tests/Dhall/Test/Diff.hs
--- a/tests/Dhall/Test/Diff.hs
+++ b/tests/Dhall/Test/Diff.hs
@@ -48,7 +48,7 @@
         expectedDiffText <- Text.IO.readFile diffFile
 
         let actualDiffDocument =
-                Diff.diffNormalized leftInput rightInput <> "\n"
+                Diff.doc (Diff.diffNormalized leftInput rightInput) <> "\n"
 
         let options =
                 Pretty.LayoutOptions
diff --git a/tests/Dhall/Test/Format.hs b/tests/Dhall/Test/Format.hs
--- a/tests/Dhall/Test/Format.hs
+++ b/tests/Dhall/Test/Format.hs
@@ -51,9 +51,10 @@
 
         inputText <- Text.IO.readFile inputFile
 
-        expr <- Core.throws (Parser.exprFromText mempty inputText)
+        (header, expr) <- Core.throws (Parser.exprAndHeaderFromText mempty inputText)
 
-        let doc        = Pretty.prettyCharacterSet characterSet  expr
+        let doc        =   Doc.pretty header
+                       <>  Pretty.prettyCharacterSet characterSet expr
         let docStream  = Doc.layoutSmart Pretty.layoutOpts doc
         let actualText = Doc.Render.Text.renderStrict docStream
 
diff --git a/tests/Dhall/Test/Lint.hs b/tests/Dhall/Test/Lint.hs
--- a/tests/Dhall/Test/Lint.hs
+++ b/tests/Dhall/Test/Lint.hs
@@ -25,9 +25,9 @@
 
 getTests :: IO TestTree
 getTests = do
-    formatTests <- Test.Util.discover (Turtle.chars <* "A.dhall") lintTest (Turtle.lstree lintDirectory)
+    lintTests <- Test.Util.discover (Turtle.chars <* "A.dhall") lintTest (Turtle.lstree lintDirectory)
 
-    let testTree = Tasty.testGroup "format tests" [ formatTests ]
+    let testTree = Tasty.testGroup "lint tests" [ lintTests ]
 
     return testTree
 
diff --git a/tests/Dhall/Test/Normalization.hs b/tests/Dhall/Test/Normalization.hs
--- a/tests/Dhall/Test/Normalization.hs
+++ b/tests/Dhall/Test/Normalization.hs
@@ -10,7 +10,6 @@
 import Test.Tasty (TestTree)
 import Turtle (FilePath, (</>))
 
-import qualified Control.Monad    as Monad
 import qualified Data.Text        as Text
 import qualified Data.Text.IO     as Text.IO
 import qualified Dhall.Context    as Context
@@ -43,14 +42,7 @@
         Test.Util.discover pattern alphaNormalizationTest
             (Turtle.lstree "./dhall-lang/tests/alpha-normalization/success/")
 
-    let unitTestFiles = do
-            path <- Turtle.lstree "./dhall-lang/tests/normalization/success/unit"
-
-            let skip = []
-
-            Monad.guard (path `notElem` skip)
-
-            return path
+    let unitTestFiles = Turtle.lstree (normalizationDirectory </> "unit/")
 
     unitTests <- Test.Util.discover pattern unitTest unitTestFiles
 
@@ -146,9 +138,11 @@
 -}
 unitTest :: Text -> TestTree
 unitTest prefix = do
+    let skip = []
+
     let prefixString = Text.unpack prefix
 
-    Tasty.HUnit.testCase prefixString $ do
+    Test.Util.testCase prefix skip $ do
         let actualPath   = prefixString <> "A.dhall"
         let expectedPath = prefixString <> "B.dhall"
 
diff --git a/tests/Dhall/Test/Parser.hs b/tests/Dhall/Test/Parser.hs
--- a/tests/Dhall/Test/Parser.hs
+++ b/tests/Dhall/Test/Parser.hs
@@ -4,7 +4,7 @@
 
 import Data.Monoid ((<>))
 import Data.Text (Text)
-import Dhall.Core (Expr, Import)
+import Dhall.Core (Binding(..), Expr(..), Import, Var(..))
 import Dhall.TypeCheck (X)
 import Prelude hiding (FilePath)
 import Test.Tasty (TestTree)
@@ -14,6 +14,7 @@
 import qualified Codec.CBOR.Term      as CBOR
 import qualified Codec.Serialise      as Serialise
 import qualified Control.Monad        as Monad
+import qualified Data.Bifunctor       as Bifunctor
 import qualified Data.ByteString      as ByteString
 import qualified Data.ByteString.Lazy as ByteString.Lazy
 import qualified Data.Text            as Text
@@ -35,49 +36,12 @@
 
 getTests :: IO TestTree
 getTests = do
-    let successFiles = do
-            path <- Turtle.lstree (parseDirectory </> "success")
-
-            let skip =
-                    -- This is a bug created by a parsing performance
-                    -- improvement
-                    [ parseDirectory </> "success/unit/MergeParenAnnotationA.dhall"
-                    ]
-
-            Monad.guard (path `notElem` skip)
-
-            return path
+    let successFiles = Turtle.lstree (parseDirectory </> "success")
 
     successTests <- do
         Test.Util.discover (Turtle.chars <* "A.dhall") shouldParse successFiles
 
-    let failureFiles = do
-            path <- Turtle.lstree (parseDirectory </> "failure")
-
-            let skip =
-                    [ -- These two unexpected successes are due to not correctly
-                      -- requiring non-empty whitespace after the `:` in a type
-                      -- annotation
-                      parseDirectory </> "failure/annotation.dhall"
-                    , parseDirectory </> "failure/unit/ImportEnvWrongEscape.dhall"
-
-                      -- Similarly, the implementation does not correctly
-                      -- require a space between a function and its argument
-                    , parseDirectory </> "failure/missingSpace.dhall"
-
-                      -- For parsing performance reasons the implementation
-                      -- treats a missing type annotation on an empty list as
-                      -- as a type-checking failure instead of a parse failure,
-                      -- but this might be fixable.
-                    , parseDirectory </> "failure/unit/ListLitEmptyAnnotation.dhall"
-                      -- The same performance improvements also broke the
-                      -- precedence of parsing empty list literals
-                    , parseDirectory </> "failure/unit/ListLitEmptyPrecedence.dhall"
-                    ]
-
-            Monad.guard (path `notElem` skip)
-
-            return path
+    let failureFiles = Turtle.lstree (parseDirectory </> "failure")
 
     failureTests <- do
         Test.Util.discover (Turtle.chars <> ".dhall") shouldNotParse failureFiles
@@ -88,14 +52,7 @@
     binaryDecodeSuccessTests <- do
         Test.Util.discover (Turtle.chars <* "A.dhallb") shouldDecode binaryDecodeSuccessFiles
 
-    let binaryDecodeFailureFiles = do
-            path <- Turtle.lstree (binaryDecodeDirectory </> "failure")
-
-            let skip = []
-
-            Monad.guard (path `notElem` skip)
-
-            return path
+    let binaryDecodeFailureFiles = Turtle.lstree (binaryDecodeDirectory </> "failure")
 
     binaryDecodeFailureTests <- do
         Test.Util.discover (Turtle.chars <* ".dhallb") shouldNotDecode binaryDecodeFailureFiles
@@ -104,17 +61,74 @@
             Tasty.testGroup "parser tests"
                 [ successTests
                 , failureTests
+                , internalTests
                 , binaryDecodeSuccessTests
                 , binaryDecodeFailureTests
                 ]
 
     return testTree
 
+internalTests :: TestTree
+internalTests =
+    Tasty.testGroup "internal"
+        [ notesInLetInLet ]
+
+notesInLetInLet :: TestTree
+notesInLetInLet = do
+    Tasty.HUnit.testCase "Notes in let-in-let" $ do
+        let code = "let x = 0 let y = 1 in let z = 2 in x"
+
+        expression <- Core.throws (Parser.exprFromText mempty code)
+
+        let simplifyNotes = Bifunctor.first Parser.srcText
+
+        let expected =
+                (Note code
+                  (Let
+                    (Binding
+                      (Just " ")
+                      "x"
+                      (Just " ")
+                      Nothing
+                      (Just " ")
+                      (Note "0 " (NaturalLit 0)))
+                    -- This 'Let' isn't wrapped in a 'Note'!
+                    (Let
+                      (Binding
+                        (Just " ")
+                        "y"
+                        (Just " ")
+                        Nothing
+                        (Just " ")
+                        (Note "1 " (NaturalLit 1))
+                      )
+                      (Note "let z = 2 in x"
+                        (Let
+                          (Binding
+                            (Just " ")
+                            "z"
+                            (Just " ")
+                            Nothing
+                            (Just " ")
+                            (Note "2 " (NaturalLit 2))
+                          )
+                          (Note "x"
+                            (Var (V "x" 0))))))))
+
+        let msg = "Unexpected parse result"
+
+        Tasty.HUnit.assertEqual msg expected (simplifyNotes expression)
+
 shouldParse :: Text -> TestTree
 shouldParse path = do
+    let skip =
+            -- This is a bug created by a parsing performance
+            -- improvement
+            [ parseDirectory </> "success/unit/MergeParenAnnotation" ]
+
     let pathString = Text.unpack path
 
-    Tasty.HUnit.testCase pathString $ do
+    Test.Util.testCase path skip $ do
         text <- Text.IO.readFile (pathString <> "A.dhall")
 
         encoded <- ByteString.Lazy.readFile (pathString <> "B.dhallb")
@@ -137,9 +151,45 @@
 
 shouldNotParse :: Text -> TestTree
 shouldNotParse path = do
+    let skip =
+            [ -- These two unexpected successes are due to not correctly
+              -- requiring non-empty whitespace after the `:` in a type
+              -- annotation
+              parseDirectory </> "failure/unit/ImportEnvWrongEscape.dhall"
+
+              -- Other spacing related unexpected successes:
+            , parseDirectory </> "failure/spacing/AnnotationNoSpace.dhall"
+            , parseDirectory </> "failure/spacing/ApplicationNoSpace1.dhall"
+            , parseDirectory </> "failure/spacing/ApplicationNoSpace2.dhall"
+            , parseDirectory </> "failure/spacing/AssertNoSpace.dhall"
+            , parseDirectory </> "failure/spacing/ForallNoSpace.dhall"
+            , parseDirectory </> "failure/spacing/ImportAltNoSpace.dhall"
+            , parseDirectory </> "failure/spacing/ImportHashedNoSpace.dhall"
+            , parseDirectory </> "failure/spacing/LambdaNoSpace.dhall"
+            , parseDirectory </> "failure/spacing/ListLitEmptyNoSpace.dhall"
+            , parseDirectory </> "failure/spacing/MergeAnnotationNoSpace3.dhall"
+            , parseDirectory </> "failure/spacing/MergeNoSpace2.dhall"
+            , parseDirectory </> "failure/spacing/NaturalPlusNoSpace.dhall"
+            , parseDirectory </> "failure/spacing/RecordTypeNoSpace.dhall"
+            , parseDirectory </> "failure/spacing/ToMapAnnotNoSpace.dhall"
+            , parseDirectory </> "failure/spacing/UnionTypeNoSpace.dhall"
+
+            , parseDirectory </> "failure/ImportHeadersExteriorHash.dhall"
+
+              -- For parsing performance reasons the implementation
+              -- treats a missing type annotation on an empty list as
+              -- as a type-checking failure instead of a parse failure,
+              -- but this might be fixable.
+            , parseDirectory </> "failure/unit/ListLitEmptyAnnotation.dhall"
+
+              -- The same performance improvements also broke the
+              -- precedence of parsing empty list literals
+            , parseDirectory </> "failure/unit/ListLitEmptyPrecedence.dhall"
+            ]
+
     let pathString = Text.unpack path
 
-    Tasty.HUnit.testCase pathString (do
+    Test.Util.testCase path skip (do
         bytes <- ByteString.readFile pathString
 
         case Text.Encoding.decodeUtf8' bytes of
@@ -147,13 +197,15 @@
             Right text -> do
                 case Parser.exprFromText mempty text of
                     Left  _ -> return ()
-                    Right _ -> fail "Unexpected successful parser" )
+                    Right _ -> Tasty.HUnit.assertFailure "Unexpected successful parse" )
 
 shouldDecode :: Text -> TestTree
 shouldDecode pathText = do
+    let skip = []
+
     let pathString = Text.unpack pathText
 
-    Tasty.HUnit.testCase pathString (do
+    Test.Util.testCase pathText skip (do
         bytes <- ByteString.Lazy.readFile (pathString <> "A.dhallb")
 
         term <- Core.throws (Serialise.deserialiseOrFail bytes)
@@ -174,13 +226,15 @@
 
 shouldNotDecode :: Text -> TestTree
 shouldNotDecode pathText = do
+    let skip = []
+
     let pathString = Text.unpack pathText
 
-    Tasty.HUnit.testCase pathString (do
+    Test.Util.testCase pathText skip (do
         bytes <- ByteString.Lazy.readFile (pathString <> ".dhallb")
 
         term <- Core.throws (Serialise.deserialiseOrFail bytes)
 
         case Binary.decodeExpression term :: Either Binary.DecodingFailure (Expr X Import) of
             Left _ -> return ()
-            Right _ -> fail "Unexpected successful decode" )
+            Right _ -> Tasty.HUnit.assertFailure "Unexpected successful decode" )
diff --git a/tests/Dhall/Test/QuickCheck.hs b/tests/Dhall/Test/QuickCheck.hs
--- a/tests/Dhall/Test/QuickCheck.hs
+++ b/tests/Dhall/Test/QuickCheck.hs
@@ -1,6 +1,8 @@
+{-# LANGUAGE DataKinds          #-}
 {-# LANGUAGE OverloadedStrings  #-}
 {-# LANGUAGE RecordWildCards    #-}
 {-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TypeOperators      #-}
 
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
@@ -8,7 +10,6 @@
 
 import Codec.Serialise (DeserialiseFailure(..))
 import Data.Either (isRight)
-import Data.List.NonEmpty (NonEmpty(..))
 import Dhall.Map (Map)
 import Dhall.Core
     ( Binding(..)
@@ -31,11 +32,12 @@
 import Dhall.Set (Set)
 import Dhall.Src (Src(..))
 import Dhall.TypeCheck (Typer)
-import Numeric.Natural (Natural)
+import Generic.Random (Weights, W, (%), (:+)(..))
 import Test.QuickCheck
     (Arbitrary(..), Gen, Positive(..), Property, NonNegative(..), genericShrink, (===), (==>))
 import Test.QuickCheck.Instances ()
 import Test.Tasty (TestTree)
+import Test.Tasty.QuickCheck (QuickCheckTests(..))
 import Text.Megaparsec (SourcePos(..), Pos)
 
 import qualified Control.Spoon
@@ -43,6 +45,7 @@
 import qualified Data.Coerce
 import qualified Data.List
 import qualified Data.Sequence
+import qualified Data.Text as Text
 import qualified Dhall.Binary
 import qualified Dhall.Context
 import qualified Dhall.Core
@@ -50,7 +53,9 @@
 import qualified Dhall.Map
 import qualified Dhall.Set
 import qualified Dhall.TypeCheck
+import qualified Generic.Random
 import qualified Test.QuickCheck
+import qualified Test.Tasty
 import qualified Test.Tasty.QuickCheck
 import qualified Text.Megaparsec       as Megaparsec
 
@@ -135,8 +140,13 @@
         .   Dhall.Map.toList
 
 instance (Arbitrary s, Arbitrary a) => Arbitrary (Binding s a) where
-    arbitrary = lift3 Binding
+    arbitrary =
+        let adapt = fmap ((,) Nothing)
+            f a b   = Binding Nothing "_" Nothing (adapt a) Nothing b
+            g a b c = Binding Nothing a   Nothing (adapt b) Nothing c
 
+        in  Test.QuickCheck.oneof [ lift2 f, lift3 g ]
+
     shrink = genericShrink
 
 instance (Arbitrary s, Arbitrary a) => Arbitrary (Chunks s a) where
@@ -156,97 +166,99 @@
 
     shrink = genericShrink
 
-averageDepth :: Natural
-averageDepth = 3
-
-averageNumberOfSubExpressions :: Double
-averageNumberOfSubExpressions = 1 - 1 / fromIntegral averageDepth
-
-probabilityOfNullaryConstructor :: Double
-probabilityOfNullaryConstructor = 1 / fromIntegral averageDepth
-
-numberOfConstructors :: Natural
-numberOfConstructors = 50
-
 instance (Arbitrary s, Arbitrary a) => Arbitrary (Expr s a) where
     arbitrary =
         Test.QuickCheck.suchThat
-            (Test.QuickCheck.frequency
-                [ ( 7, lift1 Const)
-                , ( 7, lift1 Var)
-                , ( 1, Test.QuickCheck.oneof [ lift2 (Lam "_"), lift3 Lam ])
-                , ( 1, Test.QuickCheck.oneof [ lift2 (Pi "_"), lift3 Pi ])
-                , ( 1, lift2 App)
-                , let letExpression = do
-                          n        <- Test.QuickCheck.choose (0, 2)
-                          binding  <- arbitrary
-                          bindings <- Test.QuickCheck.vectorOf n arbitrary
-                          body     <- arbitrary
-                          return (Let (binding :| bindings) body)
-                  in  ( 7, letExpression)
-                , ( 1, lift2 Annot)
-                , ( 1, lift0 Bool)
-                , ( 7, lift1 BoolLit)
-                , ( 1, lift2 BoolAnd)
-                , ( 1, lift2 BoolOr)
-                , ( 1, lift2 BoolEQ)
-                , ( 1, lift2 BoolNE)
-                , ( 1, lift3 BoolIf)
-                , ( 1, lift0 Natural)
-                , ( 7, fmap NaturalLit arbitrary)
-                , ( 1, lift0 NaturalFold)
-                , ( 1, lift0 NaturalBuild)
-                , ( 1, lift0 NaturalIsZero)
-                , ( 1, lift0 NaturalEven)
-                , ( 1, lift0 NaturalOdd)
-                , ( 1, lift0 NaturalToInteger)
-                , ( 1, lift0 NaturalShow)
-                , ( 1, lift2 NaturalPlus)
-                , ( 1, lift2 NaturalTimes)
-                , ( 1, lift0 Integer)
-                , ( 7, fmap IntegerLit integer)
-                , ( 1, lift0 IntegerShow)
-                , ( 1, lift0 Double)
-                , ( 7, lift1 DoubleLit)
-                , ( 1, lift0 DoubleShow)
-                , ( 1, lift0 Text)
-                , ( 1, lift1 TextLit)
-                , ( 1, lift2 TextAppend)
-                , ( 1, lift0 List)
-                , let listLit = do
-                          n  <- Test.QuickCheck.choose (0, 3)
-                          xs <- Test.QuickCheck.vectorOf n arbitrary
-                          let ys = Data.Sequence.fromList xs
-                          ListLit <$> arbitrary <*> pure ys
-
-                  in  ( 1, listLit)
-                , ( 1, lift2 ListAppend)
-                , ( 1, lift0 ListBuild)
-                , ( 1, lift0 ListFold)
-                , ( 1, lift0 ListLength)
-                , ( 1, lift0 ListHead)
-                , ( 1, lift0 ListLast)
-                , ( 1, lift0 ListIndexed)
-                , ( 1, lift0 ListReverse)
-                , ( 1, lift0 Optional)
-                , ( 1, lift0 OptionalFold)
-                , ( 1, lift0 OptionalBuild)
-                , ( 1, lift1 Record)
-                , ( 7, lift1 RecordLit)
-                , ( 1, lift1 Union)
-                , ( 1, lift3 UnionLit)
-                , ( 1, lift2 Combine)
-                , ( 1, lift2 CombineTypes)
-                , ( 1, lift2 Prefer)
-                , ( 1, lift3 Merge)
-                , ( 1, lift2 ToMap)
-                , ( 7, lift2 Field)
-                , ( 7, lift2 Project)
-                , ( 7, lift1 Embed)
-                ]
-            )
+            (Generic.Random.genericArbitraryRecG customGens weights)
             standardizedExpression
+      where
+        customGens
+            :: Gen Integer    -- Generates all Integer fields in Expr
+            :+ Gen Text.Text  -- Generates all Text fields in Expr
+            :+ ()
+        customGens =
+               integer
+               -- 'Lam's and 'Pi's are encoded differently when the binding is
+               -- the special string "_", so we generate some of these strings
+               -- to improve test coverage for these code paths.
+            :+ Test.QuickCheck.oneof [pure "_", arbitrary]
+            :+ ()
 
+        -- These weights determine the frequency of constructors in the generated
+        -- Expr.
+        -- They will fail to compile if the constructors don't appear in the order
+        -- in which they are defined in 'Expr'!
+        weights :: Weights (Expr s a)
+        weights =
+              (7 :: W "Const")
+            % (7 :: W "Var")
+            % (7 :: W "Lam")
+            % (7 :: W "Pi")
+            % (7 :: W "App")
+            % (7 :: W "Let")
+            % (1 :: W "Annot")
+            % (1 :: W "Bool")
+            % (7 :: W "BoolLit")
+            % (1 :: W "BoolAnd")
+            % (1 :: W "BoolOr")
+            % (1 :: W "BoolEQ")
+            % (1 :: W "BoolNE")
+            % (1 :: W "BoolIf")
+            % (1 :: W "Natural")
+            % (7 :: W "NaturalLit")
+            % (1 :: W "NaturalFold")
+            % (1 :: W "NaturalBuild")
+            % (1 :: W "NaturalIsZero")
+            % (1 :: W "NaturalEven")
+            % (1 :: W "NaturalOdd")
+            % (1 :: W "NaturalToInteger")
+            % (1 :: W "NaturalShow")
+            % (1 :: W "NaturalSubtract")
+            % (1 :: W "NaturalPlus")
+            % (1 :: W "NaturalTimes")
+            % (1 :: W "Integer")
+            % (7 :: W "IntegerLit")
+            % (1 :: W "IntegerShow")
+            % (1 :: W "IntegerToDouble")
+            % (1 :: W "Double")
+            % (7 :: W "DoubleLit")
+            % (1 :: W "DoubleShow")
+            % (1 :: W "Text")
+            % (1 :: W "TextLit")
+            % (1 :: W "TextAppend")
+            % (1 :: W "TextShow")
+            % (1 :: W "List")
+            % (1 :: W "ListLit")
+            % (1 :: W "ListAppend")
+            % (1 :: W "ListBuild")
+            % (1 :: W "ListFold")
+            % (1 :: W "ListLength")
+            % (1 :: W "ListHead")
+            % (1 :: W "ListLast")
+            % (1 :: W "ListIndexed")
+            % (1 :: W "ListReverse")
+            % (1 :: W "Optional")
+            % (7 :: W "Some")
+            % (1 :: W "None")
+            % (1 :: W "OptionalFold")
+            % (1 :: W "OptionalBuild")
+            % (1 :: W "Record")
+            % (7 :: W "RecordLit")
+            % (1 :: W "Union")
+            % (7 :: W "Combine")
+            % (1 :: W "CombineTypes")
+            % (7 :: W "Prefer")
+            % (1 :: W "Merge")
+            % (1 :: W "ToMap")
+            % (7 :: W "Field")
+            % (7 :: W "Project")
+            % (1 :: W "Assert")
+            % (1 :: W "Equivalent")
+            % (0 :: W "Note")
+            % (7 :: W "ImportAlt")
+            % (7 :: W "Embed")
+            % ()
+
     shrink expression = filter standardizedExpression (genericShrink expression)
 
 standardizedExpression :: Expr s a -> Bool
@@ -341,7 +353,7 @@
                   )
                 )
             )
-    === wrap (Right (Right expression))
+    === wrap (Right (Right (Dhall.Core.denote expression :: Expr () Import)))
   where
     wrap
         :: Either DeserialiseFailure       a
@@ -377,33 +389,42 @@
 
 isSameAsSelf :: Expr () Import -> Property
 isSameAsSelf expression =
-  hasNoImportAndTypechecks ==> Dhall.Diff.same (Dhall.Diff.diffExpression expression expression)
-  where hasNoImportAndTypechecks =
+  hasNoImportAndTypechecks ==> Dhall.Diff.same (Dhall.Diff.diff denoted denoted)
+  where denoted = Dhall.Core.denote expression
+        hasNoImportAndTypechecks =
           case traverse (\_ -> Left ()) expression of
             Right importlessExpression -> isRight (Dhall.TypeCheck.typeOf importlessExpression)
             Left _ -> False
 
 tests :: TestTree
 tests =
-    Test.Tasty.QuickCheck.testProperties
+    testProperties'
         "QuickCheck"
         [ ( "Binary serialization should round-trip"
           , Test.QuickCheck.property binaryRoundtrip
+          , QuickCheckTests 100
           )
         , ( "everything well-typed should normalize"
-          , Test.QuickCheck.property
-              (Test.QuickCheck.withMaxSuccess 10000 everythingWellTypedNormalizes)
+          , Test.QuickCheck.property everythingWellTypedNormalizes
+          , QuickCheckTests 100000
           )
         , ( "isNormalized should be consistent with normalize"
-          , Test.QuickCheck.property
-              (Test.QuickCheck.withMaxSuccess 10000 isNormalizedIsConsistentWithNormalize)
+          , Test.QuickCheck.property isNormalizedIsConsistentWithNormalize
+          , QuickCheckTests 10000
           )
         , ( "normalizeWithM should be consistent with normalize"
-          , Test.QuickCheck.property
-              (Test.QuickCheck.withMaxSuccess 10000 normalizeWithMIsConsistentWithNormalize)
+          , Test.QuickCheck.property normalizeWithMIsConsistentWithNormalize
+          , QuickCheckTests 10000
           )
         , ( "An expression should have no difference with itself"
-          , Test.QuickCheck.property
-              (Test.QuickCheck.withMaxSuccess 10000 isSameAsSelf)
+          , Test.QuickCheck.property isSameAsSelf
+          , QuickCheckTests 10000
           )
         ]
+
+testProperties' :: String -> [(String, Property, QuickCheckTests)] -> TestTree
+testProperties' name = Test.Tasty.testGroup name . map f
+  where
+    -- Using adjustOption instead of withMaxSuccess allows us to override the number of tests
+    -- with the --quickcheck-tests CLI option.
+    f (n, p, nTests) = Test.Tasty.adjustOption (max nTests) (Test.Tasty.QuickCheck.testProperty n p)
diff --git a/tests/Dhall/Test/SemanticHash.hs b/tests/Dhall/Test/SemanticHash.hs
--- a/tests/Dhall/Test/SemanticHash.hs
+++ b/tests/Dhall/Test/SemanticHash.hs
@@ -10,7 +10,6 @@
 
 import qualified Data.Text                             as Text
 import qualified Data.Text.IO                          as Text.IO
-import qualified Dhall.Binary                          as Binary
 import qualified Dhall.Core                            as Core
 import qualified Dhall.Import                          as Import
 import qualified Dhall.Parser                          as Parser
@@ -40,7 +39,7 @@
 
         let normalized = Core.alphaNormalize (Core.normalize resolved)
 
-        let actualHash = Import.hashExpressionToCode Binary.defaultStandardVersion normalized
+        let actualHash = Import.hashExpressionToCode normalized
 
         expectedHash <- Text.stripEnd <$> Text.IO.readFile (Text.unpack hashFile)
 
diff --git a/tests/Dhall/Test/Tutorial.hs b/tests/Dhall/Test/Tutorial.hs
--- a/tests/Dhall/Test/Tutorial.hs
+++ b/tests/Dhall/Test/Tutorial.hs
@@ -33,7 +33,6 @@
         , Test.Tasty.testGroup "Unions"
             [ example 0 "./tests/tutorial/unions0A.dhall" "./tests/tutorial/unions0B.dhall"
             , example 1 "./tests/tutorial/unions1A.dhall" "./tests/tutorial/unions1B.dhall"
-            , example 2 "./tests/tutorial/unions2A.dhall" "./tests/tutorial/unions2B.dhall"
             , example 3 "./tests/tutorial/unions3A.dhall" "./tests/tutorial/unions3B.dhall"
             , example 4 "./tests/tutorial/unions4A.dhall" "./tests/tutorial/unions4B.dhall"
             ]
diff --git a/tests/Dhall/Test/TypeCheck.hs b/tests/Dhall/Test/TypeCheck.hs
--- a/tests/Dhall/Test/TypeCheck.hs
+++ b/tests/Dhall/Test/TypeCheck.hs
@@ -10,7 +10,6 @@
 import Turtle (FilePath, (</>))
 
 import qualified Control.Exception as Exception
-import qualified Control.Monad     as Monad
 import qualified Data.Text         as Text
 import qualified Dhall.Core        as Core
 import qualified Dhall.Parser      as Parser
@@ -25,16 +24,11 @@
 
 getTests :: IO TestTree
 getTests = do
-    successTests <- Test.Util.discover (Turtle.chars <* "A.dhall") successTest (Turtle.lstree (typecheckDirectory </> "success"))
-
-    let failureTestFiles = do
-            path <- Turtle.lstree (typecheckDirectory </> "failure")
-
-            let skip = []
+    let successTestFiles = Turtle.lstree (typecheckDirectory </> "success")
 
-            Monad.guard (path `notElem` skip)
+    successTests <- Test.Util.discover (Turtle.chars <* "A.dhall") successTest successTestFiles
 
-            return path
+    let failureTestFiles = Turtle.lstree (typecheckDirectory </> "failure")
 
     failureTests <- Test.Util.discover (Turtle.chars <> ".dhall") failureTest failureTestFiles
 
@@ -46,26 +40,39 @@
     return testTree
 
 successTest :: Text -> TestTree
-successTest prefix =
-    Tasty.HUnit.testCase (Text.unpack prefix) $ do
+successTest prefix = do
+    let skip = []
+
+    Test.Util.testCase prefix skip $ do
         let actualCode   = Test.Util.toDhallPath (prefix <> "A.dhall")
         let expectedCode = Test.Util.toDhallPath (prefix <> "B.dhall")
 
-        actualExpr <- Core.throws (Parser.exprFromText mempty actualCode)
-
+        actualExpr   <- Core.throws (Parser.exprFromText mempty actualCode  )
         expectedExpr <- Core.throws (Parser.exprFromText mempty expectedCode)
 
         let annotatedExpr = Core.Annot actualExpr expectedExpr
 
-        resolvedExpr <- Test.Util.load annotatedExpr
+        tryResolvedExpr <- Exception.try (Test.Util.load annotatedExpr)
 
+        resolvedExpr <- case tryResolvedExpr of
+            Left  exception    -> Tasty.HUnit.assertFailure (show (exception :: SomeException))
+            Right resolvedExpr -> return resolvedExpr
+
+        case TypeCheck.typeOf resolvedExpr of
+            Left  exception -> Tasty.HUnit.assertFailure (show exception)
+            Right _         -> return ()
+{-
         _ <- Core.throws (TypeCheck.typeOf resolvedExpr)
+-}
 
         return ()
 
 failureTest :: Text -> TestTree
 failureTest path = do
-    Tasty.HUnit.testCase (Text.unpack path) $ do
+    let skip = [ typecheckDirectory </> "failure/unit/MergeEmptyNeedsDirectAnnotation1.dhall"
+               ]
+
+    Test.Util.testCase path skip $ do
         let dhallPath = Test.Util.toDhallPath path
 
         expression <- Core.throws (Parser.exprFromText mempty dhallPath)
@@ -81,5 +88,5 @@
         typeChecked <- Exception.handle handler io
 
         if typeChecked
-            then fail (Text.unpack path <> " should not have type-checked")
+            then Tasty.HUnit.assertFailure (Text.unpack path <> " should not have type-checked")
             else return ()
diff --git a/tests/Dhall/Test/TypeInference.hs b/tests/Dhall/Test/TypeInference.hs
--- a/tests/Dhall/Test/TypeInference.hs
+++ b/tests/Dhall/Test/TypeInference.hs
@@ -6,6 +6,7 @@
 import Data.Text (Text)
 import Prelude hiding (FilePath)
 import Test.Tasty (TestTree)
+import Turtle (FilePath, (</>))
 
 import qualified Data.Text         as Text
 import qualified Data.Text.IO      as Text.IO
@@ -18,10 +19,15 @@
 import qualified Test.Tasty.HUnit  as Tasty.HUnit
 import qualified Turtle
 
+typeInferenceDirectory :: FilePath
+typeInferenceDirectory = "./dhall-lang/tests/type-inference"
+
 getTests :: IO TestTree
 getTests = do
-    successTests <- Test.Util.discover (Turtle.chars <* "A.dhall") successTest (Turtle.lstree "./dhall-lang/tests/type-inference/success")
+    let successTestFiles = Turtle.lstree (typeInferenceDirectory </> "success")
 
+    successTests <- Test.Util.discover (Turtle.chars <* "A.dhall") successTest successTestFiles
+
     let testTree = Tasty.testGroup "type-inference tests"
             [ successTests
             ]
@@ -30,12 +36,21 @@
 
 successTest :: Text -> TestTree
 successTest prefix = do
-    Tasty.HUnit.testCase (Text.unpack prefix) $ do
+    let skip = [ -- We correctly infer the expected type @NaN ≡ NaN@ here,
+                 -- but the comparison between the inferred and the expected type
+                 -- fails due to `Expr`'s 'Eq' instance, which inherits the
+                 -- @NaN /= NaN@ inequality from 'Double'.
+                 typeInferenceDirectory </> "success/unit/AssertNaN"
+               ]
+
+    Test.Util.testCase prefix skip $ do
         value <- expr "A.dhall"
 
         expectedType <- expr "B.dhall"
 
-        inferredType <- Core.throws (TypeCheck.typeOf value)
+        inferredType <- case TypeCheck.typeOf value of
+            Left  exception    -> Tasty.HUnit.assertFailure (show exception)
+            Right inferredType -> return inferredType
 
         let message = "The inferred type did not match the expected type"
 
diff --git a/tests/Dhall/Test/Util.hs b/tests/Dhall/Test/Util.hs
--- a/tests/Dhall/Test/Util.hs
+++ b/tests/Dhall/Test/Util.hs
@@ -16,6 +16,7 @@
     , assertTypeChecks
     , assertDoesntTypeCheck
     , discover
+    , Dhall.Test.Util.testCase
     , toDhallPath
     ) where
 
@@ -25,6 +26,7 @@
 import Dhall.Context (Context)
 import Dhall.Core (Expr, Normalizer, ReifiedNormalizer(..), Import)
 import Dhall.Import (Status)
+import Data.Monoid((<>))
 import Dhall.Parser (Src)
 import Dhall.TypeCheck (X)
 import Prelude hiding (FilePath)
@@ -33,16 +35,17 @@
 import Turtle (FilePath, Pattern, Shell, fp)
 
 import qualified Control.Exception
-import qualified Control.Foldl     as Foldl
+import qualified Control.Foldl                    as Foldl
 import qualified Data.Functor
-import qualified Data.Text         as Text
+import qualified Data.Text                        as Text
 import qualified Dhall.Context
 import qualified Dhall.Core
 import qualified Dhall.Import
 import qualified Dhall.Parser
 import qualified Dhall.TypeCheck
 import qualified Control.Monad.Trans.State.Strict as State
-import qualified Test.Tasty        as Tasty
+import qualified Test.Tasty                       as Tasty
+import qualified Test.Tasty.ExpectedFailure       as Tasty.ExpectedFailure
 import qualified Turtle
 
 #ifndef WITH_HTTP
@@ -199,6 +202,13 @@
 
     return (Tasty.testGroup "discover" tests)
 
+testCase :: Text -> [ FilePath ] -> Assertion -> TestTree
+testCase prefix skip assertion =
+    if prefix `elem` map (Turtle.format fp) skip
+    then Tasty.ExpectedFailure.expectFail test
+    else test
+  where
+    test = Test.Tasty.HUnit.testCase (Text.unpack prefix) assertion
 
 {-| Path names on Windows are not valid Dhall paths due to using backslashes
     instead of forwardslashes to separate path components.  This utility fixes
diff --git a/tests/diff/appList.txt b/tests/diff/appList.txt
--- a/tests/diff/appList.txt
+++ b/tests/diff/appList.txt
@@ -1,4 +1,4 @@
   λ(… :   …
         → …)
-→ …@…
+→ …
   …
diff --git a/tests/diff/emptyList.txt b/tests/diff/emptyList.txt
new file mode 100644
--- /dev/null
+++ b/tests/diff/emptyList.txt
@@ -0,0 +1,2 @@
+- [] : …
++ True
diff --git a/tests/diff/emptyListA.dhall b/tests/diff/emptyListA.dhall
new file mode 100644
--- /dev/null
+++ b/tests/diff/emptyListA.dhall
@@ -0,0 +1,1 @@
+[] : List Natural
diff --git a/tests/diff/emptyListB.dhall b/tests/diff/emptyListB.dhall
new file mode 100644
--- /dev/null
+++ b/tests/diff/emptyListB.dhall
@@ -0,0 +1,1 @@
+True
diff --git a/tests/diff/function.txt b/tests/diff/function.txt
new file mode 100644
--- /dev/null
+++ b/tests/diff/function.txt
@@ -0,0 +1,6 @@
+  …
+→ …
+→ …@- 1
+    + 0
+  
+→ …
diff --git a/tests/diff/functionA.dhall b/tests/diff/functionA.dhall
new file mode 100644
--- /dev/null
+++ b/tests/diff/functionA.dhall
@@ -0,0 +1,1 @@
+∀(a : Type) → ∀(b : Type) → ∀(x : a) → Bool
diff --git a/tests/diff/functionB.dhall b/tests/diff/functionB.dhall
new file mode 100644
--- /dev/null
+++ b/tests/diff/functionB.dhall
@@ -0,0 +1,1 @@
+∀(a : Type) → ∀(b : Type) → ∀(x : b) → Bool
diff --git a/tests/diff/nonEmptyList.txt b/tests/diff/nonEmptyList.txt
new file mode 100644
--- /dev/null
+++ b/tests/diff/nonEmptyList.txt
@@ -0,0 +1,2 @@
+- [ … ]
++ True
diff --git a/tests/diff/nonEmptyListA.dhall b/tests/diff/nonEmptyListA.dhall
new file mode 100644
--- /dev/null
+++ b/tests/diff/nonEmptyListA.dhall
@@ -0,0 +1,1 @@
+[1]
diff --git a/tests/diff/nonEmptyListB.dhall b/tests/diff/nonEmptyListB.dhall
new file mode 100644
--- /dev/null
+++ b/tests/diff/nonEmptyListB.dhall
@@ -0,0 +1,1 @@
+True
diff --git a/tests/format/headerA.dhall b/tests/format/headerA.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/headerA.dhall
@@ -0,0 +1,4 @@
+   
+{- bla -}
+  
+True
diff --git a/tests/format/headerB.dhall b/tests/format/headerB.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/headerB.dhall
@@ -0,0 +1,3 @@
+{- bla -}
+  
+True
diff --git a/tests/format/issue1301A.dhall b/tests/format/issue1301A.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/issue1301A.dhall
@@ -0,0 +1,5 @@
+let attribute
+    : Text → Text → { mapKey : Text, mapValue : Text }
+    = λ(key : Text) → λ(value : Text) → { mapKey = key, mapValue = value }
+
+in  attribute
diff --git a/tests/format/issue1301B.dhall b/tests/format/issue1301B.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/issue1301B.dhall
@@ -0,0 +1,5 @@
+let attribute
+    : Text → Text → { mapKey : Text, mapValue : Text }
+    = λ(key : Text) → λ(value : Text) → { mapKey = key, mapValue = value }
+
+in  attribute
diff --git a/tests/format/letA.dhall b/tests/format/letA.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/letA.dhall
@@ -0,0 +1,1 @@
+let x = "Lorem ipsum" let y = "Lorem ipsum" in let z = "Lorem ipsum" in x ++ y ++ z
diff --git a/tests/format/letB.dhall b/tests/format/letB.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/letB.dhall
@@ -0,0 +1,5 @@
+let x = "Lorem ipsum"
+
+let y = "Lorem ipsum"
+
+in  let z = "Lorem ipsum" in x ++ y ++ z
diff --git a/tests/format/letCommentsA.dhall b/tests/format/letCommentsA.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/letCommentsA.dhall
@@ -0,0 +1,7 @@
+let {- Example documentation for a let binding
+       that spans more than one line
+    -}
+    x {- we can interject things here -} = -- Make sure one-line comments work
+        1
+
+in  x
diff --git a/tests/format/letCommentsB.dhall b/tests/format/letCommentsB.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/letCommentsB.dhall
@@ -0,0 +1,8 @@
+let {- Example documentation for a let binding
+       that spans more than one line
+    -}
+    x {- we can interject things here -} =
+    -- Make sure one-line comments work
+      1
+
+in  x
diff --git a/tests/format/letLongCommentsA.dhall b/tests/format/letLongCommentsA.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/letLongCommentsA.dhall
@@ -0,0 +1,3 @@
+let x {- foo                                        -} : {- bar                                           -} Bool {- baz                           -} = {- bla                      -} True
+
+in  x
diff --git a/tests/format/letLongCommentsB.dhall b/tests/format/letLongCommentsB.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/letLongCommentsB.dhall
@@ -0,0 +1,5 @@
+let x
+    {- foo                                        -} : {- bar                                           -} Bool
+    = {- bla                      -} True
+
+in  x
diff --git a/tests/format/letNewlineCommentsA.dhall b/tests/format/letNewlineCommentsA.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/letNewlineCommentsA.dhall
@@ -0,0 +1,7 @@
+let x = 1
+in
+let {- aaaaaaaaaaaaaaaaaaa
+    -} y : {- bbbbbbbbbbbbbbbbbbbbb
+    -} Natural {- cccccccccccccc
+    -} = {- ddddddddddddddddd -} 2
+    in x
diff --git a/tests/format/letNewlineCommentsB.dhall b/tests/format/letNewlineCommentsB.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/letNewlineCommentsB.dhall
@@ -0,0 +1,9 @@
+let x = 1
+
+in  let {- aaaaaaaaaaaaaaaaaaa
+        -} y
+        : {- bbbbbbbbbbbbbbbbbbbbb
+          -} Natural
+        = {- ddddddddddddddddd -} 2
+    
+    in  x
diff --git a/tests/format/letShortCommentsA.dhall b/tests/format/letShortCommentsA.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/letShortCommentsA.dhall
@@ -0,0 +1,3 @@
+let x = True
+let {- 0 -} y {- 1 -} : {- 2 -} Bool = {- 3-} False
+in x
diff --git a/tests/format/letShortCommentsB.dhall b/tests/format/letShortCommentsB.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/letShortCommentsB.dhall
@@ -0,0 +1,1 @@
+let x = True let {- 0 -} y {- 1 -} : {- 2 -} Bool = {- 3-} False in x
diff --git a/tests/format/unicodeA.dhall b/tests/format/unicodeA.dhall
--- a/tests/format/unicodeA.dhall
+++ b/tests/format/unicodeA.dhall
@@ -6,7 +6,7 @@
     , separator =
         Some "┃"
     , alignment =
-          < ToTheLeft = {=} | ToTheRight : {} | Centered : {} >
+          < ToTheLeft | ToTheRight | Centered >.ToTheLeft
         : ./Alignment.dhall
     , barWidth =
         None Natural
diff --git a/tests/format/unicodeB.dhall b/tests/format/unicodeB.dhall
--- a/tests/format/unicodeB.dhall
+++ b/tests/format/unicodeB.dhall
@@ -6,8 +6,7 @@
     , separator =
         Some "┃"
     , alignment =
-          < ToTheLeft = {=} | ToTheRight : {} | Centered : {} >
-        : ./Alignment.dhall
+        < ToTheLeft | ToTheRight | Centered >.ToTheLeft : ./Alignment.dhall
     , barWidth =
         None Natural
     , barSegments =
diff --git a/tests/format/urlsA.dhall b/tests/format/urlsA.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/urlsA.dhall
@@ -0,0 +1,13 @@
+let unreserved = http://x/y%7ez
+
+let uppercasehex = http://x/y%3bz
+
+let reserved = http://x/y:z
+
+let quoted = http://x/"y:z"
+
+let quotedPercent = http://x/"y%z"
+
+let snowman = http://x/"y☃z"
+
+in "done"
diff --git a/tests/format/urlsB.dhall b/tests/format/urlsB.dhall
new file mode 100644
--- /dev/null
+++ b/tests/format/urlsB.dhall
@@ -0,0 +1,13 @@
+let unreserved = http://x/y~z
+
+let uppercasehex = http://x/y%3Bz
+
+let reserved = http://x/y:z
+
+let quoted = http://x/y%3Az
+
+let quotedPercent = http://x/y%25z
+
+let snowman = http://x/y%E2%98%83z
+
+in  "done"
diff --git a/tests/lint/success/assertA.dhall b/tests/lint/success/assertA.dhall
new file mode 100644
--- /dev/null
+++ b/tests/lint/success/assertA.dhall
@@ -0,0 +1,14 @@
+let simpleAssert = assert : 1 + 1 ≡ 2
+
+let assertIn1Lam = λ(n : Natural) → assert : Natural/subtract 0 n ≡ n
+
+let assertIn2Lams =
+        λ(m : Natural)
+      → λ(n : Natural)
+      → assert : Natural/subtract m m ≡ Natural/subtract n n
+
+let assertInLetInLam = λ(m : Natural) → let n = m + 0 in assert : m ≡ n
+
+let unusedNonAssert = "Foo"
+
+in  {=}
diff --git a/tests/lint/success/assertB.dhall b/tests/lint/success/assertB.dhall
new file mode 100644
--- /dev/null
+++ b/tests/lint/success/assertB.dhall
@@ -0,0 +1,12 @@
+let simpleAssert = assert : 1 + 1 ≡ 2
+
+let assertIn1Lam = λ(n : Natural) → assert : Natural/subtract 0 n ≡ n
+
+let assertIn2Lams =
+        λ(m : Natural)
+      → λ(n : Natural)
+      → assert : Natural/subtract m m ≡ Natural/subtract n n
+
+let assertInLetInLam = λ(m : Natural) → let n = m + 0 in assert : m ≡ n
+
+in  {=}
diff --git a/tests/recursive/expr0.dhall b/tests/recursive/expr0.dhall
new file mode 100644
--- /dev/null
+++ b/tests/recursive/expr0.dhall
@@ -0,0 +1,20 @@
+  λ(Expr : Type)
+→ let ExprF =
+        < LitF :
+            { _1 : Natural }
+        | AddF :
+            { _1 : Expr, _2 : Expr }
+        | MulF :
+            { _1 : Expr, _2 : Expr }
+        >
+  
+  in    λ(Fix : ExprF → Expr)
+      → let Lit = λ(x : Natural) → Fix (ExprF.LitF { _1 = x })
+        
+        let Add =
+              λ(x : Expr) → λ(y : Expr) → Fix (ExprF.AddF { _1 = x, _2 = y })
+        
+        let Mul =
+              λ(x : Expr) → λ(y : Expr) → Fix (ExprF.MulF { _1 = x, _2 = y })
+        
+        in  Add (Mul (Lit 3) (Lit 7)) (Add (Lit 1) (Lit 2))
diff --git a/tests/recursive/expr1.dhall b/tests/recursive/expr1.dhall
new file mode 100644
--- /dev/null
+++ b/tests/recursive/expr1.dhall
@@ -0,0 +1,18 @@
+  λ(a : Type)
+→ let ExprF =
+        < LitF :
+            { _1 : Natural }
+        | AddF :
+            { _1 : a, _2 : a }
+        | MulF :
+            { _1 : a, _2 : a }
+        >
+  
+  in    λ(a : ExprF → a)
+      → let Lit = λ(x : Natural) → a (ExprF.LitF { _1 = x })
+        
+        let Add = λ(x : a@1) → λ(y : a@1) → a (ExprF.AddF { _1 = x, _2 = y })
+        
+        let Mul = λ(x : a@1) → λ(y : a@1) → a (ExprF.MulF { _1 = x, _2 = y })
+        
+        in  Add (Mul (Lit 3) (Lit 7)) (Add (Lit 1) (Lit 2))
diff --git a/tests/tutorial/Union.dhall b/tests/tutorial/Union.dhall
new file mode 100644
--- /dev/null
+++ b/tests/tutorial/Union.dhall
@@ -0,0 +1,1 @@
+< Left : Natural | Right : Bool>
diff --git a/tests/tutorial/unions0A.dhall b/tests/tutorial/unions0A.dhall
--- a/tests/tutorial/unions0A.dhall
+++ b/tests/tutorial/unions0A.dhall
@@ -1,1 +1,1 @@
-./process.dhall < Left = 3 | Right : Bool >
+./process.dhall ((./Union.dhall).Left 3)
diff --git a/tests/tutorial/unions1A.dhall b/tests/tutorial/unions1A.dhall
--- a/tests/tutorial/unions1A.dhall
+++ b/tests/tutorial/unions1A.dhall
@@ -1,1 +1,1 @@
-./process.dhall < Right = True | Left : Natural >
+./process.dhall ((./Union.dhall).Right True)
diff --git a/tests/tutorial/unions2A.dhall b/tests/tutorial/unions2A.dhall
deleted file mode 100644
--- a/tests/tutorial/unions2A.dhall
+++ /dev/null
@@ -1,8 +0,0 @@
-    let Empty  = < Empty = {=} | Person : { name : Text, age : Natural } >
-in  let Person =
-        λ(p : { name : Text, age : Natural }) → < Person = p | Empty : {} >
-in  [   Empty
-    ,   Person { name = "John", age = 23 }
-    ,   Person { name = "Amy" , age = 25 }
-    ,   Empty
-    ]
diff --git a/tests/tutorial/unions2B.dhall b/tests/tutorial/unions2B.dhall
deleted file mode 100644
--- a/tests/tutorial/unions2B.dhall
+++ /dev/null
@@ -1,5 +0,0 @@
-[ < Empty = {=} | Person : { age : Natural, name : Text } >
-, < Person = { age = 23, name = "John" } | Empty : {} >
-, < Person = { age = 25, name = "Amy" } | Empty : {} >
-, < Empty = {=} | Person : { age : Natural, name : Text } >
-]
