diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,85 @@
+1.24.0
+
+* Supports version 8.0.0 of the standard
+    * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v8.0.0
+* BREAKING CHANGE: Allow tabs and blank lines in multi-line strings
+    * Blank lines are now ignored for the purpose of dedenting multiline strings
+    * Lines with leading tabs (or mixed tabs and spaces) are now dedented, too,
+      so long as they all share the same prefix
+    * This is technically a breaking change, but unlikely to affect programs
+      in practice, especially if they were formatted with `dhall format`.  This
+      change mainly affects programs that were not indented correctly.
+    * See the changelog for standard version 8.0.0 for more details
+* BREAKING CHANGE: Simplify bare interpolations
+    * Expressions like `λ(x : Text) → "${x}"` now simplify to `λ(x : Text) → x`
+    * This is a technically breaking change because it changes how these sorts
+      of expressions are serialized.  This does not affect semantic integrity
+      checks and the new simplified expressions are extensionally equivalent to
+      their older counterpart expressions.
+    * See the changelog for standard version 8.0.0 for more details
+* BREAKING CHANGE: Encode integrity check as multihash
+    * Semantic integrity checks are now encoded using the multihash spec
+    * This is a technically breaking change that does not perturb the hash for
+      user-facing semantic integrity checks.  This only affects how expressions
+      with unresolved imports are serialized, but semantic integrity checks are
+      only computed for fully-resolved imports.
+    * See the changelog for standard version 8.0.0 for more details
+* BUG FIX: Fix type-checker to reject invalid record type annotations
+    * e.g. `{ x = 1 } : { x : Text }` was not properly rejected by the type
+      checker
+    * See: https://github.com/dhall-lang/dhall-haskell/pull/965
+* BUG FIX: Custom header forwarding fixed
+    * Forwarding custom headers could previously fail in various ways, such as:
+        * Cyclic imports leading to endless network requests
+        * Resolving a non-existent import for the custom headers
+        * Resolving an existing but incorrect import for the custom headers
+    * This change fixes that by forwarding custom headers by value instead of
+      by reference
+    * See: https://github.com/dhall-lang/dhall-haskell/pull/967
+* BUG FIX: Fix GHCJS support
+    * `Natural/fold` was broken in version 1.22, which this change fixes
+    * Specifically, it would hang for `Natural` numbers greater than 1
+    * See: https://github.com/dhall-lang/dhall-haskell/pull/985
+* BUG FIX: `dhall diff` no longer double-prints key-value separators
+    * See: https://github.com/dhall-lang/dhall-haskell/pull/952
+* Feature: Record projection by expression
+    * You can now project out a subset of record fields by the expected type
+    * `let t = { x : Natural } let p = { x = 1, y = 2 } in p.(t) = { x = 1 }`
+    * See the changelog for standard version 8.0.0 for more details
+* Feature: Inline headers
+    * You no longer need to specify custom headers in a separate import.  You
+      can now specify them inline within the same file.
+    * e.g.: `https://example.com/x using [ { header = "Foo", value = "Bar" } ]`
+    * See the changelog for standard version 8.0.0 for more details
+* Feature: Allow `Sort` as a type annotation
+    * An expression such as `Kind → Kind : Sort` will now type-check
+    * `Sort` is still disallowed outside of a type annotation
+    * See the changelog for standard version 8.0.0 for more details
+* Feature: Allow self-describe-cbor when decoding
+    * Dhall expressions serialized as CBOR can be tagged to describe themselves
+      as CBOR without affecting decoding
+    * See the changelog for standard version 8.0.0 for more details
+* Feature: New `--file` option for `dhall` commands
+    * In other words, instead of `dhall <<< './some/file` you can now use
+      `dhall --file some/file`
+    * See: https://github.com/dhall-lang/dhall-haskell/pull/949
+* Feature: New `--cache` flag for `dhall freeze` command
+    * This automates the idiom used by the Prelude to optimistically cache
+      imports but gracefully degrade if the semantic integrity check fails
+    * See: https://github.com/dhall-lang/dhall-haskell/pull/980
+* Feature: Add `:clear` command to `dhall repl`
+    * This deletes previous bindings from the history so that they can be
+      garbage collected
+    * See: https://github.com/dhall-lang/dhall-haskell/pull/966
+* Feature: New `chunkExprs` `Traversal` added to `Dhall.Core`
+    * See: https://github.com/dhall-lang/dhall-haskell/pull/954
+* Feature: New `Dhall.Optics` module
+    * This re-exports some convenient @lens@ utilities used internally for
+      packages trying to avoid a @lens@ dependency
+    * See: https://github.com/dhall-lang/dhall-haskell/pull/986
+* More GHC 8.8 support
+    * See: https://github.com/dhall-lang/dhall-haskell/pull/961
+
 1.23.0
 
 * BREAKING CHANGE: Fix marshaling union literals
diff --git a/benchmark/dhall-command/Main.hs b/benchmark/dhall-command/Main.hs
--- a/benchmark/dhall-command/Main.hs
+++ b/benchmark/dhall-command/Main.hs
@@ -8,7 +8,7 @@
 
 options :: Main.Options
 options = Main.Options
-  { Main.mode = Main.Default False False
+  { Main.mode = Main.Default Nothing False False
   , Main.explain = False
   , Main.plain = False
   , Main.ascii = False
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
@@ -10,9 +10,9 @@
 ./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 and
+    : List Bool → Bool
+    =   λ(xs : List Bool)
+      → List/fold Bool xs Bool (λ(l : Bool) → λ(r : Bool) → l && r) 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
@@ -9,9 +9,9 @@
 ./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 build
+    : (∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool) → Bool
+    =   λ(f : ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool)
+      → f Bool True 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
@@ -14,9 +14,9 @@
 ./even ([] : List Bool) = True
 ```
 -}
-    let even
-        : List Bool → Bool
-        =   λ(xs : List Bool)
-          → List/fold Bool xs Bool (λ(x : Bool) → λ(y : Bool) → x == y) True
+let even
+    : List Bool → Bool
+    =   λ(xs : List Bool)
+      → List/fold Bool xs Bool (λ(x : Bool) → λ(y : Bool) → x == y) 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
@@ -9,12 +9,12 @@
 ./fold False Natural 0 1 = 1
 ```
 -}
-    let fold
-        : ∀(b : Bool) → ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool
-        =   λ(b : Bool)
-          → λ(bool : Type)
-          → λ(true : bool)
-          → λ(false : bool)
-          → if b then true else false
+let fold
+    : ∀(b : Bool) → ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool
+    =   λ(b : Bool)
+      → λ(bool : Type)
+      → λ(true : bool)
+      → λ(false : bool)
+      → if b then true else false
 
 in  fold
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
@@ -14,9 +14,9 @@
 ./odd ([] : List Bool) = False
 ```
 -}
-    let odd
-        : List Bool → Bool
-        =   λ(xs : List Bool)
-          → List/fold Bool xs Bool (λ(x : Bool) → λ(y : Bool) → x != y) False
+let odd
+    : List Bool → Bool
+    =   λ(xs : List Bool)
+      → List/fold Bool xs Bool (λ(x : Bool) → λ(y : Bool) → x != y) 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
@@ -10,9 +10,9 @@
 ./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 or
+    : List Bool → Bool
+    =   λ(xs : List Bool)
+      → List/fold Bool xs Bool (λ(l : Bool) → λ(r : Bool) → l || r) False
 
 in  or
diff --git a/dhall-lang/Prelude/Bool/package.dhall b/dhall-lang/Prelude/Bool/package.dhall
--- a/dhall-lang/Prelude/Bool/package.dhall
+++ b/dhall-lang/Prelude/Bool/package.dhall
@@ -1,25 +1,25 @@
 { and =
-    ./and sha256:0b2114fa33cd76652e4360f012bc082718944fe4c5b28c975483178f8d9b0a6d
+      ./and sha256:0b2114fa33cd76652e4360f012bc082718944fe4c5b28c975483178f8d9b0a6d
     ? ./and
 , build =
-    ./build sha256:add7cb9acacac705410088d876a7e4488e046a7aded304f06c51accffd7f1b7b
+      ./build sha256:add7cb9acacac705410088d876a7e4488e046a7aded304f06c51accffd7f1b7b
     ? ./build
 , even =
-    ./even sha256:72a05ee550636a3acb768360fa51ba0db0326763e0cf1ceb737f0f3607fc0fe5
+      ./even sha256:72a05ee550636a3acb768360fa51ba0db0326763e0cf1ceb737f0f3607fc0fe5
     ? ./even
 , fold =
-    ./fold sha256:39f60baf3950268c2e849e91dc6279ee41cd6b81892d54020d4fcd2ce30a96ae
+      ./fold sha256:39f60baf3950268c2e849e91dc6279ee41cd6b81892d54020d4fcd2ce30a96ae
     ? ./fold
 , not =
-    ./not sha256:723df402df24377d8a853afed08d9d69a0a6d86e2e5b2bac8960b0d4756c7dc4
+      ./not sha256:723df402df24377d8a853afed08d9d69a0a6d86e2e5b2bac8960b0d4756c7dc4
     ? ./not
 , odd =
-    ./odd sha256:6360fca3a745de32bd186cc7b71487a6398cd47d5119064eae491872c41d1999
+      ./odd sha256:6360fca3a745de32bd186cc7b71487a6398cd47d5119064eae491872c41d1999
     ? ./odd
 , or =
-    ./or sha256:5c50738e84e1c4fed8343ebd57608500e1b61ac1f502aa52d6d6edb5c20b99e4
+      ./or sha256:5c50738e84e1c4fed8343ebd57608500e1b61ac1f502aa52d6d6edb5c20b99e4
     ? ./or
 , show =
-    ./show sha256:f85f6d2d921c37a2122cb2e2f8a0170e305b699debd0e6df5ef3370d806b5f61
+      ./show sha256:f85f6d2d921c37a2122cb2e2f8a0170e305b699debd0e6df5ef3370d806b5f61
     ? ./show
 }
diff --git a/dhall-lang/Prelude/Double/package.dhall b/dhall-lang/Prelude/Double/package.dhall
--- a/dhall-lang/Prelude/Double/package.dhall
+++ b/dhall-lang/Prelude/Double/package.dhall
@@ -1,4 +1,4 @@
 { show =
-    ./show sha256:ae645813cc4d8505a265df4d7564c95482f62bb3e07fc81681959599b6cee04f
+      ./show sha256:ae645813cc4d8505a265df4d7564c95482f62bb3e07fc81681959599b6cee04f
     ? ./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
@@ -8,14 +8,14 @@
 = True
 ```
 -}
-    let compose
-        : ∀(a : Type) → ∀(b : Type) → ∀(c : Type) → (a → b) → (b → c) → a → c
-        =   λ(A : Type)
-          → λ(B : Type)
-          → λ(C : Type)
-          → λ(f : A → B)
-          → λ(g : B → C)
-          → λ(x : A)
-          → g (f x)
+let compose
+    : ∀(a : Type) → ∀(b : Type) → ∀(c : Type) → (a → b) → (b → c) → a → c
+    =   λ(A : Type)
+      → λ(B : Type)
+      → λ(C : Type)
+      → λ(f : A → B)
+      → λ(g : B → C)
+      → λ(x : A)
+      → g (f x)
 
 in  compose
diff --git a/dhall-lang/Prelude/Function/package.dhall b/dhall-lang/Prelude/Function/package.dhall
--- a/dhall-lang/Prelude/Function/package.dhall
+++ b/dhall-lang/Prelude/Function/package.dhall
@@ -1,4 +1,4 @@
 { compose =
-    ./compose sha256:65ad8bbea530b3d8968785a7cf4a9a7976b67059aa15e3b61fcba600a40ae013
+      ./compose sha256:65ad8bbea530b3d8968785a7cf4a9a7976b67059aa15e3b61fcba600a40ae013
     ? ./compose
 }
diff --git a/dhall-lang/Prelude/Integer/package.dhall b/dhall-lang/Prelude/Integer/package.dhall
--- a/dhall-lang/Prelude/Integer/package.dhall
+++ b/dhall-lang/Prelude/Integer/package.dhall
@@ -1,7 +1,7 @@
 { show =
-    ./show sha256:ecf8b0594cd5181bc45d3b7ea0d44d3ba9ad5dac6ec17bb8968beb65f4b1baa9
+      ./show sha256:ecf8b0594cd5181bc45d3b7ea0d44d3ba9ad5dac6ec17bb8968beb65f4b1baa9
     ? ./show
 , toDouble =
-    ./toDouble sha256:77bc5d635dc4d952f37cc96f2a681d5ac503b4e8b21fc00055b1946adb5beda7
+      ./toDouble sha256:77bc5d635dc4d952f37cc96f2a681d5ac503b4e8b21fc00055b1946adb5beda7
     ? ./toDouble
 }
diff --git a/dhall-lang/Prelude/JSON/Nesting b/dhall-lang/Prelude/JSON/Nesting
--- a/dhall-lang/Prelude/JSON/Nesting
+++ b/dhall-lang/Prelude/JSON/Nesting
@@ -5,17 +5,16 @@
 For example, this Dhall code:
 
 ```
-    let Example = < Left : { foo : Natural } | Right : { bar : Bool } >
-
-in  let example = constructors Example
-
-in  let Nesting = < Inline : {} | Nested : Text >
+let Example = < Left : { foo : Natural } | Right : { bar : Bool } >
 
-in  let nesting = constructors Nesting
+let Nesting = < Inline | Nested : Text >
 
-in  { field    = "name"
-    , nesting  = nesting.Inline {=}
-    , contents = example.Left { foo = 2 }
+in  { field =
+        "name"
+    , nesting =
+        Nesting.Inline
+    , contents =
+        Example.Left { foo = 2 }
     }
 ```
 
@@ -29,4 +28,4 @@
 ```
 
 -}
-let Nesting : Type = < Inline : {} | Nested : Text > in Nesting
+let Nesting : Type = < Inline | Nested : Text > in Nesting
diff --git a/dhall-lang/Prelude/JSON/Tagged b/dhall-lang/Prelude/JSON/Tagged
--- a/dhall-lang/Prelude/JSON/Tagged
+++ b/dhall-lang/Prelude/JSON/Tagged
@@ -5,33 +5,31 @@
 For example, this code:
 
 ```
-    let map = ../List/map
-
-in  let Provisioner =
-          < shell :
-              { inline : List Text }
-          | file :
-              { source : Text, destination : Text }
-          >
+let map = ../List/map
 
-in  let provisioner = constructors Provisioner
+let Provisioner =
+      < shell :
+          { inline : List Text }
+      | file :
+          { source : Text, destination : Text }
+      >
 
-in  let Tagged = ./Tagged
+let Tagged = ./Tagged
 
-in  let nesting = constructors ./Nesting
+let Nesting = ./Nesting
 
-in  let wrap
-        : Provisioner → Tagged Provisioner
-        =   λ(x : Provisioner)
-          → { field = "type", nesting = nesting.Nested "params", contents = x }
+let wrap
+    : Provisioner → Tagged Provisioner
+    =   λ(x : Provisioner)
+      → { field = "type", nesting = Nesting.Nested "params", contents = x }
 
 in  { provisioners =
         map
         Provisioner
         (Tagged Provisioner)
         wrap
-        [ provisioner.shell { inline = [ "echo foo" ] }
-        , provisioner.file
+        [ Provisioner.shell { inline = [ "echo foo" ] }
+        , Provisioner.file
           { source = "app.tar.gz", destination = "/tmp/app.tar.gz" }
         ]
     }
@@ -62,8 +60,8 @@
 ```
 
 -}
-    let Tagged
-        : Type → Type
-        = λ(a : Type) → { field : Text, nesting : ./Nesting, contents : a }
+let Tagged
+    : Type → Type
+    = λ(a : Type) → { field : Text, nesting : ./Nesting, contents : a }
 
 in  Tagged
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
@@ -11,7 +11,7 @@
 ```
 -}
 
-    let keyText =
-          λ(key : Text) → λ(value : Text) → { mapKey = key, mapValue = value }
+let keyText =
+      λ(key : Text) → λ(value : Text) → { mapKey = key, mapValue = value }
 
 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
@@ -11,10 +11,10 @@
 ```
 -}
 
-    let keyValue =
-            λ(v : Type)
-          → λ(key : Text)
-          → λ(value : v)
-          → { mapKey = key, mapValue = value }
+let keyValue =
+        λ(v : Type)
+      → λ(key : Text)
+      → λ(value : v)
+      → { mapKey = key, mapValue = value }
 
 in  keyValue
diff --git a/dhall-lang/Prelude/JSON/package.dhall b/dhall-lang/Prelude/JSON/package.dhall
--- a/dhall-lang/Prelude/JSON/package.dhall
+++ b/dhall-lang/Prelude/JSON/package.dhall
@@ -1,7 +1,7 @@
 { keyText =
-    ./keyText sha256:f7b6c802ca5764d03d5e9a6e48d9cb167c01392f775d9c2c87b83cdaa60ea0cc
+      ./keyText sha256:f7b6c802ca5764d03d5e9a6e48d9cb167c01392f775d9c2c87b83cdaa60ea0cc
     ? ./keyText
 , keyValue =
-    ./keyValue sha256:a0a97199d280c4cce72ffcbbf93b7ceda0a569cf4d173ac98e0aaaa78034b98c
+      ./keyValue sha256:a0a97199d280c4cce72ffcbbf93b7ceda0a569cf4d173ac98e0aaaa78034b98c
     ? ./keyValue
 }
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
@@ -10,11 +10,11 @@
 ./all Natural Natural/even ([] : List Natural) = True
 ```
 -}
-    let all
-        : ∀(a : Type) → (a → Bool) → List a → Bool
-        =   λ(a : Type)
-          → λ(f : a → Bool)
-          → λ(xs : List a)
-          → List/fold a xs Bool (λ(x : a) → λ(r : Bool) → f x && r) True
+let all
+    : ∀(a : Type) → (a → Bool) → List a → Bool
+    =   λ(a : Type)
+      → λ(f : a → Bool)
+      → λ(xs : List a)
+      → List/fold a xs Bool (λ(x : a) → λ(r : Bool) → f x && r) 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
@@ -10,11 +10,11 @@
 ./any Natural Natural/even ([] : List Natural) = False
 ```
 -}
-    let any
-        : ∀(a : Type) → (a → Bool) → List a → Bool
-        =   λ(a : Type)
-          → λ(f : a → Bool)
-          → λ(xs : List a)
-          → List/fold a xs Bool (λ(x : a) → λ(r : Bool) → f x || r) False
+let any
+    : ∀(a : Type) → (a → Bool) → List a → Bool
+    =   λ(a : Type)
+      → λ(f : a → Bool)
+      → λ(xs : List a)
+      → List/fold a xs Bool (λ(x : a) → λ(r : Bool) → f x || r) 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
@@ -23,10 +23,10 @@
 = [] : List Text
 ```
 -}
-    let build
-        :   ∀(a : Type)
-          → (∀(list : Type) → ∀(cons : a → list → list) → ∀(nil : list) → list)
-          → List a
-        = List/build
+let build
+    :   ∀(a : Type)
+      → (∀(list : Type) → ∀(cons : a → list → list) → ∀(nil : list) → list)
+      → List a
+    = List/build
 
 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
@@ -22,21 +22,21 @@
 ./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
-            )
+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
+        )
 
 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
@@ -12,17 +12,17 @@
 = [] : List Natural
 ```
 -}
-    let concatMap
-        : ∀(a : Type) → ∀(b : Type) → (a → List b) → List a → List b
-        =   λ(a : Type)
-          → λ(b : Type)
-          → λ(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)
-            )
+let concatMap
+    : ∀(a : Type) → ∀(b : Type) → (a → List b) → List a → List b
+    =   λ(a : Type)
+      → λ(b : Type)
+      → λ(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)
+        )
 
 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
@@ -11,20 +11,20 @@
 = [ 3, 5 ]
 ```
 -}
-    let filter
-        : ∀(a : Type) → (a → Bool) → List a → List a
-        =   λ(a : Type)
-          → λ(f : a → Bool)
-          → λ(xs : List a)
-          → List/build
+let filter
+    : ∀(a : Type) → (a → Bool) → List a → List a
+    =   λ(a : Type)
+      → λ(f : a → Bool)
+      → λ(xs : List a)
+      → List/build
+        a
+        (   λ(list : Type)
+          → λ(cons : a → list → list)
+          → List/fold
             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)
-            )
+            xs
+            list
+            (λ(x : a) → λ(xs : list) → if f x then cons x xs else xs)
+        )
 
 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
@@ -34,13 +34,13 @@
 →   cons 2 (cons 3 (cons 5 nil))
 ```
 -}
-    let fold
-        :   ∀(a : Type)
-          → List a
-          → ∀(list : Type)
-          → ∀(cons : a → list → list)
-          → ∀(nil : list)
-          → list
-        = List/fold
+let fold
+    :   ∀(a : Type)
+      → List a
+      → ∀(list : Type)
+      → ∀(cons : a → list → list)
+      → ∀(nil : list)
+      → list
+    = List/fold
 
 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
@@ -10,29 +10,29 @@
 ./generate 0 Bool Natural/even = [] : List Bool
 ```
 -}
-    let generate
-        : Natural → ∀(a : Type) → (Natural → a) → List a
-        =   λ(n : Natural)
-          → λ(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 {=})
-                    )
-                  )
+let generate
+    : Natural → ∀(a : Type) → (Natural → a) → List a
+    =   λ(n : Natural)
+      → λ(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 {=})
                 )
-                list
-                (λ(x : { index : Natural, value : {} }) → cons (f x.index))
+              )
             )
+            list
+            (λ(x : { index : Natural, value : {} }) → cons (f x.index))
+        )
 
 in  generate
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
@@ -14,8 +14,8 @@
 = [] : List { index : Natural, value : Bool }
 ```
 -}
-    let indexed
-        : ∀(a : Type) → List a → List { index : Natural, value : a }
-        = List/indexed
+let indexed
+    : ∀(a : Type) → List a → List { index : Natural, value : a }
+    = List/indexed
 
 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
@@ -12,32 +12,32 @@
 = [] : List Natural
 ```
 -}
-    let iterate
-        : Natural → ∀(a : Type) → (a → a) → a → List a
-        =   λ(n : Natural)
-          → λ(a : Type)
-          → λ(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 {=})
-                    )
-                  )
-                )
-                list
-                (   λ(y : { index : Natural, value : {} })
-                  → cons (Natural/fold y.index a f x)
+let iterate
+    : Natural → ∀(a : Type) → (a → a) → a → List a
+    =   λ(n : Natural)
+      → λ(a : Type)
+      → λ(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 {=})
                 )
+              )
             )
+            list
+            (   λ(y : { index : Natural, value : {} })
+              → cons (Natural/fold y.index a f x)
+            )
+        )
 
 in  iterate
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
@@ -11,17 +11,17 @@
 = [] : List Bool
 ```
 -}
-    let map
-        : ∀(a : Type) → ∀(b : Type) → (a → b) → List a → List b
-        =   λ(a : Type)
-          → λ(b : Type)
-          → λ(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))
-            )
+let map
+    : ∀(a : Type) → ∀(b : Type) → (a → b) → List a → List b
+    =   λ(a : Type)
+      → λ(b : Type)
+      → λ(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))
+        )
 
 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
@@ -9,8 +9,8 @@
 ./null Natural ([] : List Natural) = True
 ```
 -}
-    let null
-        : ∀(a : Type) → List a → Bool
-        = λ(a : Type) → λ(xs : List a) → Natural/isZero (List/length a xs)
+let null
+    : ∀(a : Type) → List a → Bool
+    = λ(a : Type) → λ(xs : List a) → Natural/isZero (List/length a xs)
 
 in  null
diff --git a/dhall-lang/Prelude/List/package.dhall b/dhall-lang/Prelude/List/package.dhall
--- a/dhall-lang/Prelude/List/package.dhall
+++ b/dhall-lang/Prelude/List/package.dhall
@@ -1,58 +1,58 @@
 { all =
-    ./all sha256:7ac5bb6f77e9ffe9e2356d90968d39764a9a32f75980206e6b12f815bb83dd15
+      ./all sha256:7ac5bb6f77e9ffe9e2356d90968d39764a9a32f75980206e6b12f815bb83dd15
     ? ./all
 , any =
-    ./any sha256:b8e9e13b25e799f342a81f6eda4075906eb1a19dfdcb10a0ca25925eba4033b8
+      ./any sha256:b8e9e13b25e799f342a81f6eda4075906eb1a19dfdcb10a0ca25925eba4033b8
     ? ./any
 , build =
-    ./build sha256:8cf73fc1e115cfcb79bb9cd490bfcbd45c824e93c57a0e64c86c0c72e9ebbe42
+      ./build sha256:8cf73fc1e115cfcb79bb9cd490bfcbd45c824e93c57a0e64c86c0c72e9ebbe42
     ? ./build
 , concat =
-    ./concat sha256:54e43278be13276e03bd1afa89e562e94a0a006377ebea7db14c7562b0de292b
+      ./concat sha256:54e43278be13276e03bd1afa89e562e94a0a006377ebea7db14c7562b0de292b
     ? ./concat
 , concatMap =
-    ./concatMap sha256:3b2167061d11fda1e4f6de0522cbe83e0d5ac4ef5ddf6bb0b2064470c5d3fb64
+      ./concatMap sha256:3b2167061d11fda1e4f6de0522cbe83e0d5ac4ef5ddf6bb0b2064470c5d3fb64
     ? ./concatMap
 , filter =
-    ./filter sha256:8ebfede5bbfe09675f246c33eb83964880ac615c4b1be8d856076fdbc4b26ba6
+      ./filter sha256:8ebfede5bbfe09675f246c33eb83964880ac615c4b1be8d856076fdbc4b26ba6
     ? ./filter
 , fold =
-    ./fold sha256:10bb945c25ab3943bd9df5a32e633cbfae112b7d3af38591784687e436a8d814
+      ./fold sha256:10bb945c25ab3943bd9df5a32e633cbfae112b7d3af38591784687e436a8d814
     ? ./fold
 , generate =
-    ./generate sha256:78ff1ad96c08b88a8263eea7bc8381c078225cfcb759c496f792edb5a5e0b1a4
+      ./generate sha256:78ff1ad96c08b88a8263eea7bc8381c078225cfcb759c496f792edb5a5e0b1a4
     ? ./generate
 , head =
-    ./head sha256:0d2e65ba0aea908377e46d22020dc3ad970284f4ee4eb8e6b8c51e53038c0026
+      ./head sha256:0d2e65ba0aea908377e46d22020dc3ad970284f4ee4eb8e6b8c51e53038c0026
     ? ./head
 , indexed =
-    ./indexed sha256:58bb44457fa81adf26f5123c1b2e8bef0c5aa22dac5fa5ebdfb7da84563b027f
+      ./indexed sha256:58bb44457fa81adf26f5123c1b2e8bef0c5aa22dac5fa5ebdfb7da84563b027f
     ? ./indexed
 , iterate =
-    ./iterate sha256:e4999ccce190a2e2a6ab9cb188e3af6c40df474087827153005293f11bfe1d26
+      ./iterate sha256:e4999ccce190a2e2a6ab9cb188e3af6c40df474087827153005293f11bfe1d26
     ? ./iterate
 , last =
-    ./last sha256:741226b741af152a1638491cdff7f3aa74baf080ada2e63429483f3d195a984d
+      ./last sha256:741226b741af152a1638491cdff7f3aa74baf080ada2e63429483f3d195a984d
     ? ./last
 , length =
-    ./length sha256:42c6812c7a9e3c6e6fad88f77c5b3849503964e071cb784e22c38c888a401461
+      ./length sha256:42c6812c7a9e3c6e6fad88f77c5b3849503964e071cb784e22c38c888a401461
     ? ./length
 , map =
-    ./map sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680
+      ./map sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680
     ? ./map
 , null =
-    ./null sha256:2338e39637e9a50d66ae1482c0ed559bbcc11e9442bfca8f8c176bbcd9c4fc80
+      ./null sha256:2338e39637e9a50d66ae1482c0ed559bbcc11e9442bfca8f8c176bbcd9c4fc80
     ? ./null
 , replicate =
-    ./replicate sha256:d4250b45278f2d692302489ac3e78280acb238d27541c837ce46911ff3baa347
+      ./replicate sha256:d4250b45278f2d692302489ac3e78280acb238d27541c837ce46911ff3baa347
     ? ./replicate
 , reverse =
-    ./reverse sha256:ad99d224d61852de6696da5a7d04c98dbe676fe67d5e4ef4f19e9aaa27006e9d
+      ./reverse sha256:ad99d224d61852de6696da5a7d04c98dbe676fe67d5e4ef4f19e9aaa27006e9d
     ? ./reverse
 , shifted =
-    ./shifted sha256:54fb22c7e952ebce1cfc0fcdd33ce4cfa817bff9d6564af268dea6685f8b5dfe
+      ./shifted sha256:54fb22c7e952ebce1cfc0fcdd33ce4cfa817bff9d6564af268dea6685f8b5dfe
     ? ./shifted
 , unzip =
-    ./unzip sha256:4d6003e9e683a289fe33f4c90f958eb1e08ea0bbb474210fcd90d1885c9660e9
+      ./unzip sha256:4d6003e9e683a289fe33f4c90f958eb1e08ea0bbb474210fcd90d1885c9660e9
     ? ./unzip
 }
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
@@ -9,16 +9,16 @@
 ./replicate 0 Natural 1 = [] : List Natural
 ```
 -}
-    let replicate
-        : Natural → ∀(a : Type) → a → List a
-        =   λ(n : Natural)
-          → λ(a : Type)
-          → λ(x : a)
-          → List/build
-            a
-            (   λ(list : Type)
-              → λ(cons : a → list → list)
-              → Natural/fold n list (cons x)
-            )
+let replicate
+    : Natural → ∀(a : Type) → a → List a
+    =   λ(n : Natural)
+      → λ(a : Type)
+      → λ(x : a)
+      → List/build
+        a
+        (   λ(list : Type)
+          → λ(cons : a → list → list)
+          → Natural/fold n list (cons x)
+        )
 
 in  replicate
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
@@ -35,56 +35,52 @@
 = [] : List { index : Natural, value : Bool }
 ```
 -}
-    let shifted
-        :   ∀(a : Type)
-          → List (List { index : Natural, value : a })
-          → List { index : Natural, value : a }
-        =   λ(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
-            )
+let shifted
+    :   ∀(a : Type)
+      → List (List { index : Natural, value : a })
+      → List { index : Natural, value : a }
+    =   λ(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
+        )
 
 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
@@ -20,36 +20,36 @@
 = { _1 = [] : List Text, _2 = [] : List Bool }
 ```
 -}
-    let unzip
-        :   ∀(a : Type)
-          → ∀(b : Type)
-          → List { _1 : a, _2 : b }
-          → { _1 : List a, _2 : List b }
-        =   λ(a : Type)
-          → λ(b : Type)
-          → λ(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)
-                )
-            , _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)
-                )
-            }
+let unzip
+    :   ∀(a : Type)
+      → ∀(b : Type)
+      → List { _1 : a, _2 : b }
+      → { _1 : List a, _2 : List b }
+    =   λ(a : Type)
+      → λ(b : Type)
+      → λ(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)
+            )
+        , _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)
+            )
+        }
 
 in  unzip
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
@@ -21,13 +21,13 @@
 = 0
 ```
 -}
-    let build
-        :   (   ∀(natural : Type)
-              → ∀(succ : natural → natural)
-              → ∀(zero : natural)
-              → natural
-            )
-          → Natural
-        = Natural/build
+let build
+    :   (   ∀(natural : Type)
+          → ∀(succ : natural → natural)
+          → ∀(zero : natural)
+          → natural
+        )
+      → Natural
+    = Natural/build
 
 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
@@ -10,27 +10,27 @@
 ./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 {=})
-                    )
-                  )
+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 {=})
                 )
-                list
-                (λ(x : { index : Natural, value : {} }) → cons x.index)
+              )
             )
+            list
+            (λ(x : { index : Natural, value : {} }) → cons x.index)
+        )
 
 in  enumerate
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
@@ -22,12 +22,12 @@
 →   succ (succ (succ zero))
 ```
 -}
-    let fold
-        :   Natural
-          → ∀(natural : Type)
-          → ∀(succ : natural → natural)
-          → ∀(zero : natural)
-          → natural
-        = Natural/fold
+let fold
+    :   Natural
+      → ∀(natural : Type)
+      → ∀(succ : natural → natural)
+      → ∀(zero : natural)
+      → natural
+    = Natural/fold
 
 in  fold
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
@@ -1,34 +1,34 @@
 { build =
-    ./build sha256:e7e25e6c4f1d8e573606ed1bef725396ac2de5c68f7c5d329ffc5822085b984c
+      ./build sha256:e7e25e6c4f1d8e573606ed1bef725396ac2de5c68f7c5d329ffc5822085b984c
     ? ./build
 , enumerate =
-    ./enumerate sha256:0cf083980a752b21ce0df9fc2222a4c139f50909e2353576e26a191002aa1ce3
+      ./enumerate sha256:0cf083980a752b21ce0df9fc2222a4c139f50909e2353576e26a191002aa1ce3
     ? ./enumerate
 , even =
-    ./even sha256:b85b8b56892dfef881e1c0e79eade0b949528f792aac0ea42432b315ede4ee66
+      ./even sha256:b85b8b56892dfef881e1c0e79eade0b949528f792aac0ea42432b315ede4ee66
     ? ./even
 , fold =
-    ./fold sha256:fd01c931e585a8f5fd049af7b076b862ea164f1813b34800c7616a49e549ee06
+      ./fold sha256:fd01c931e585a8f5fd049af7b076b862ea164f1813b34800c7616a49e549ee06
     ? ./fold
 , isZero =
-    ./isZero sha256:1be98236800ed2d5cff44f16ca02b34b0c37dfa239d9e0d63d9d2c6eeae3d1d1
+      ./isZero sha256:1be98236800ed2d5cff44f16ca02b34b0c37dfa239d9e0d63d9d2c6eeae3d1d1
     ? ./isZero
 , odd =
-    ./odd sha256:ab3c729262c642ec1cdb72a81e910fcfaf2aea13e3961d0bf1bec83efea5aac5
+      ./odd sha256:ab3c729262c642ec1cdb72a81e910fcfaf2aea13e3961d0bf1bec83efea5aac5
     ? ./odd
 , product =
-    ./product sha256:e3e6fd76207875b81d39f79fdbc90b5e640444c04fb3d84c2c9326748f0b26e6
+      ./product sha256:e3e6fd76207875b81d39f79fdbc90b5e640444c04fb3d84c2c9326748f0b26e6
     ? ./product
 , sum =
-    ./sum sha256:33f7f4c3aff62e5ecf4848f964363133452d420dcde045784518fb59fa970037
+      ./sum sha256:33f7f4c3aff62e5ecf4848f964363133452d420dcde045784518fb59fa970037
     ? ./sum
 , show =
-    ./show sha256:684ed560ad86f438efdea229eca122c29e8e14f397ed32ec97148d578ca5aa21
+      ./show sha256:684ed560ad86f438efdea229eca122c29e8e14f397ed32ec97148d578ca5aa21
     ? ./show
 , toDouble =
-    ./toDouble sha256:d5eb52143dcd35b46a6f0cdb2d3cbf31a14b6daeba56e29066f8e344c9fb6e81
+      ./toDouble sha256:d5eb52143dcd35b46a6f0cdb2d3cbf31a14b6daeba56e29066f8e344c9fb6e81
     ? ./toDouble
 , toInteger =
-    ./toInteger sha256:160d2d278619f3da34a1f4f02e739a447e4f2aa5a2978c45b710515b41491e1f
+      ./toInteger sha256:160d2d278619f3da34a1f4f02e739a447e4f2aa5a2978c45b710515b41491e1f
     ? ./toInteger
 }
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
@@ -9,14 +9,9 @@
 ./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 product
+    : List Natural → Natural
+    =   λ(xs : List Natural)
+      → List/fold Natural xs Natural (λ(l : Natural) → λ(r : Natural) → l * r) 1
 
 in  product
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
@@ -9,14 +9,9 @@
 ./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 sum
+    : List Natural → Natural
+    =   λ(xs : List Natural)
+      → List/fold Natural xs Natural (λ(l : Natural) → λ(r : Natural) → l + r) 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
@@ -9,8 +9,8 @@
 ./toDouble 0 = 0.0
 ```
 -}
-    let toDouble
-        : Natural → Double
-        = λ(n : Natural) → Integer/toDouble (Natural/toInteger n)
+let toDouble
+    : Natural → Double
+    = λ(n : Natural) → Integer/toDouble (Natural/toInteger n)
 
 in  toDouble
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
@@ -10,11 +10,11 @@
 ./all Natural Natural/even (None Natural) = True
 ```
 -}
-    let all
-        : ∀(a : Type) → (a → Bool) → Optional a → Bool
-        =   λ(a : Type)
-          → λ(f : a → Bool)
-          → λ(xs : Optional a)
-          → Optional/fold a xs Bool f True
+let all
+    : ∀(a : Type) → (a → Bool) → Optional a → Bool
+    =   λ(a : Type)
+      → λ(f : a → Bool)
+      → λ(xs : Optional a)
+      → Optional/fold a xs Bool f 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
@@ -10,11 +10,11 @@
 ./any Natural Natural/even (None Natural) = False
 ```
 -}
-    let any
-        : ∀(a : Type) → (a → Bool) → Optional a → Bool
-        =   λ(a : Type)
-          → λ(f : a → Bool)
-          → λ(xs : Optional a)
-          → Optional/fold a xs Bool f False
+let any
+    : ∀(a : Type) → (a → Bool) → Optional a → Bool
+    =   λ(a : Type)
+      → λ(f : a → Bool)
+      → λ(xs : Optional a)
+      → Optional/fold a xs Bool f 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
@@ -23,14 +23,14 @@
 = None Natural
 ```
 -}
-    let build
-        :   ∀(a : Type)
-          → (   ∀(optional : Type)
-              → ∀(some : a → optional)
-              → ∀(none : optional)
-              → optional
-            )
-          → Optional a
-        = Optional/build
+let build
+    :   ∀(a : Type)
+      → (   ∀(optional : Type)
+          → ∀(some : a → optional)
+          → ∀(none : optional)
+          → optional
+        )
+      → Optional a
+    = Optional/build
 
 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
@@ -14,15 +14,15 @@
 = 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)
+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)
 
 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
@@ -11,22 +11,22 @@
 = None Natural
 ```
 -}
-    let filter
-        : ∀(a : Type) → (a → Bool) → Optional a → Optional a
-        =   λ(a : Type)
-          → λ(f : a → Bool)
-          → λ(xs : Optional a)
-          → Optional/build
+let filter
+    : ∀(a : Type) → (a → Bool) → Optional a → Optional a
+    =   λ(a : Type)
+      → λ(f : a → Bool)
+      → λ(xs : Optional a)
+      → Optional/build
+        a
+        (   λ(optional : Type)
+          → λ(some : a → optional)
+          → λ(none : optional)
+          → Optional/fold
             a
-            (   λ(optional : Type)
-              → λ(some : a → optional)
-              → λ(none : optional)
-              → Optional/fold
-                a
-                xs
-                optional
-                (λ(x : a) → if f x then some x else none)
-                none
-            )
+            xs
+            optional
+            (λ(x : a) → if f x then some x else none)
+            none
+        )
 
 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
@@ -9,13 +9,13 @@
 ./fold Natural (None Natural) Natural (λ(x : Natural) → x) 0 = 0
 ```
 -}
-    let fold
-        :   ∀(a : Type)
-          → Optional a
-          → ∀(optional : Type)
-          → ∀(some : a → optional)
-          → ∀(none : optional)
-          → optional
-        = Optional/fold
+let fold
+    :   ∀(a : Type)
+      → Optional a
+      → ∀(optional : Type)
+      → ∀(some : a → optional)
+      → ∀(none : optional)
+      → optional
+    = Optional/fold
 
 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
@@ -11,18 +11,18 @@
 ./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)
+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)
 
 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
@@ -11,18 +11,18 @@
 ./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)
+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)
 
 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
@@ -9,10 +9,10 @@
 ./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 length
+    : ∀(a : Type) → Optional a → Natural
+    =   λ(a : Type)
+      → λ(xs : Optional a)
+      → Optional/fold a xs Natural (λ(_ : a) → 1) 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
@@ -9,12 +9,12 @@
 ./map Natural Bool Natural/even (None Natural) = None Bool
 ```
 -}
-    let map
-        : ∀(a : Type) → ∀(b : Type) → (a → b) → Optional a → Optional b
-        =   λ(a : Type)
-          → λ(b : Type)
-          → λ(f : a → b)
-          → λ(o : Optional a)
-          → Optional/fold a o (Optional b) (λ(x : a) → Some (f x)) (None b)
+let map
+    : ∀(a : Type) → ∀(b : Type) → (a → b) → Optional a → Optional b
+    =   λ(a : Type)
+      → λ(b : Type)
+      → λ(f : a → b)
+      → λ(o : Optional a)
+      → Optional/fold a o (Optional b) (λ(x : a) → Some (f x)) (None b)
 
 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
@@ -9,10 +9,10 @@
 ./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 null
+    : ∀(a : Type) → Optional a → Bool
+    =   λ(a : Type)
+      → λ(xs : Optional a)
+      → Optional/fold a xs Bool (λ(_ : a) → False) True
 
 in  null
diff --git a/dhall-lang/Prelude/Optional/package.dhall b/dhall-lang/Prelude/Optional/package.dhall
--- a/dhall-lang/Prelude/Optional/package.dhall
+++ b/dhall-lang/Prelude/Optional/package.dhall
@@ -1,40 +1,40 @@
 { all =
-    ./all sha256:b9b015fe8be14da940901aa1510ee1d5e205df37ee651c32ac975a799782c410
+      ./all sha256:b9b015fe8be14da940901aa1510ee1d5e205df37ee651c32ac975a799782c410
     ? ./all
 , any =
-    ./any sha256:0a637c0f2cc7d30b8f0bca021d2ee1ad1213fb9d9712c669b29feab66a590eaf
+      ./any sha256:0a637c0f2cc7d30b8f0bca021d2ee1ad1213fb9d9712c669b29feab66a590eaf
     ? ./any
 , build =
-    ./build sha256:f331299d1279cfb88dd25a5acfdd64130900991b6154239ad343a2883f6eb50c
+      ./build sha256:f331299d1279cfb88dd25a5acfdd64130900991b6154239ad343a2883f6eb50c
     ? ./build
 , concat =
-    ./concat sha256:b49a3b7dc49eb83d150977caa5ae347be1cbbe14e3b6d0e07349bd2e5f707d69
+      ./concat sha256:b49a3b7dc49eb83d150977caa5ae347be1cbbe14e3b6d0e07349bd2e5f707d69
     ? ./concat
 , filter =
-    ./filter sha256:b3d5e19a6cec592a76c12167a9e5e1e76649e776229d70a11c77b76cd29f617e
+      ./filter sha256:b3d5e19a6cec592a76c12167a9e5e1e76649e776229d70a11c77b76cd29f617e
     ? ./filter
 , fold =
-    ./fold sha256:62139ff410ca84302acebe763a8a1794420dd472d907384c7fb80df2a2180302
+      ./fold sha256:62139ff410ca84302acebe763a8a1794420dd472d907384c7fb80df2a2180302
     ? ./fold
 , head =
-    ./head sha256:b0b5d257294515f1de35f24fa83e54d7f1d5ebca9c3c1fc903a80ab40e19b3a6
+      ./head sha256:b0b5d257294515f1de35f24fa83e54d7f1d5ebca9c3c1fc903a80ab40e19b3a6
     ? ./head
 , last =
-    ./last sha256:f839221a8a04adae6c501458eb264e7f4e375a1facb294cb80caacfd012a6765
+      ./last sha256:f839221a8a04adae6c501458eb264e7f4e375a1facb294cb80caacfd012a6765
     ? ./last
 , length =
-    ./length sha256:722a3754a411c053f006a32c506a6d1b14869c2ab799169df9cdac346edf07d3
+      ./length sha256:722a3754a411c053f006a32c506a6d1b14869c2ab799169df9cdac346edf07d3
     ? ./length
 , map =
-    ./map sha256:e7f44219250b89b094fbf9996e04b5daafc0902d864113420072ae60706ac73d
+      ./map sha256:e7f44219250b89b094fbf9996e04b5daafc0902d864113420072ae60706ac73d
     ? ./map
 , null =
-    ./null sha256:efc43103e49b56c5bf089db8e0365bbfc455b8a2f0dc6ee5727a3586f85969fd
+      ./null sha256:efc43103e49b56c5bf089db8e0365bbfc455b8a2f0dc6ee5727a3586f85969fd
     ? ./null
 , toList =
-    ./toList sha256:390fe99619e9a25e71a253a2b33011f9e5fa26a7d990795205543d1edd72ce5b
+      ./toList sha256:390fe99619e9a25e71a253a2b33011f9e5fa26a7d990795205543d1edd72ce5b
     ? ./toList
 , unzip =
-    ./unzip sha256:7b517bc2a8a4dbec044c6bea5e059cafde5a0cb1d3a5e7d13d346c9327a00f30
+      ./unzip sha256:7b517bc2a8a4dbec044c6bea5e059cafde5a0cb1d3a5e7d13d346c9327a00f30
     ? ./unzip
 }
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
@@ -9,10 +9,10 @@
 ./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 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)
 
 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
@@ -11,28 +11,28 @@
 = { _1 = None Text, _2 = None Bool }
 ```
 -}
-    let unzip
-        :   ∀(a : Type)
-          → ∀(b : Type)
-          → Optional { _1 : a, _2 : b }
-          → { _1 : Optional a, _2 : Optional b }
-        =   λ(a : Type)
-          → λ(b : Type)
-          → λ(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)
-            , _2 =
-                Optional/fold
-                { _1 : a, _2 : b }
-                xs
-                (Optional b)
-                (λ(x : { _1 : a, _2 : b }) → Some x._2)
-                (None b)
-            }
+let unzip
+    :   ∀(a : Type)
+      → ∀(b : Type)
+      → Optional { _1 : a, _2 : b }
+      → { _1 : Optional a, _2 : Optional b }
+    =   λ(a : Type)
+      → λ(b : Type)
+      → λ(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)
+        , _2 =
+            Optional/fold
+            { _1 : a, _2 : b }
+            xs
+            (Optional b)
+            (λ(x : { _1 : a, _2 : b }) → Some x._2)
+            (None b)
+        }
 
 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
@@ -9,9 +9,9 @@
 ./concat ([] : List Text) = ""
 ```
 -}
-    let concat
-        : List Text → Text
-        =   λ(xs : List Text)
-          → List/fold Text xs Text (λ(x : Text) → λ(y : Text) → x ++ y) ""
+let concat
+    : List Text → Text
+    =   λ(xs : List Text)
+      → List/fold Text xs Text (λ(x : Text) → λ(y : Text) → x ++ y) ""
 
 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
@@ -11,11 +11,11 @@
 = ""
 ```
 -}
-    let concatMap
-        : ∀(a : Type) → (a → Text) → List a → Text
-        =   λ(a : Type)
-          → λ(f : a → Text)
-          → λ(xs : List a)
-          → List/fold a xs Text (λ(x : a) → λ(y : Text) → f x ++ y) ""
+let concatMap
+    : ∀(a : Type) → (a → Text) → List a → Text
+    =   λ(a : Type)
+      → λ(f : a → Text)
+      → λ(xs : List a)
+      → List/fold a xs Text (λ(x : a) → λ(y : Text) → f x ++ y) ""
 
 in  concatMap
diff --git a/dhall-lang/Prelude/Text/package.dhall b/dhall-lang/Prelude/Text/package.dhall
--- a/dhall-lang/Prelude/Text/package.dhall
+++ b/dhall-lang/Prelude/Text/package.dhall
@@ -1,16 +1,16 @@
 { concat =
-    ./concat sha256:35e20d9403fbadb1a0061edb84e076ed56313709fa4bc8124d86ff54896f20ac
+      ./concat sha256:35e20d9403fbadb1a0061edb84e076ed56313709fa4bc8124d86ff54896f20ac
     ? ./concat
 , concatMap =
-    ./concatMap sha256:175d893ad7f2b2c05fff9e32f0d9cbadc7f5fce57945071508cf3603f8aa298e
+      ./concatMap sha256:175d893ad7f2b2c05fff9e32f0d9cbadc7f5fce57945071508cf3603f8aa298e
     ? ./concatMap
 , concatMapSep =
-    ./concatMapSep sha256:46b81a9e211fb8278bf2793e75e8175fef79e0e3e478ef1016e3233ecc2ddfe6
+      ./concatMapSep sha256:46b81a9e211fb8278bf2793e75e8175fef79e0e3e478ef1016e3233ecc2ddfe6
     ? ./concatMapSep
 , concatSep =
-    ./concatSep sha256:d28e61f5057a240e857e09dba1b040fa3477bddb9659c5606c760852a9165890
+      ./concatSep sha256:d28e61f5057a240e857e09dba1b040fa3477bddb9659c5606c760852a9165890
     ? ./concatSep
 , show =
-    ./show sha256:c9dc5de3e5f32872dbda57166804865e5e80785abe358ff61f1d8ac45f1f4784
+      ./show sha256:c9dc5de3e5f32872dbda57166804865e5e80785abe358ff61f1d8ac45f1f4784
     ? ./show
 }
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
@@ -1,28 +1,28 @@
-{ `Bool` =
+{ Bool =
       ./Bool/package.dhall sha256:7ee950e7c2142be5923f76d00263e536b71d96cb9c190d7743c1679501ddeb0a
     ? ./Bool/package.dhall
-, `Double` =
+, Double =
       ./Double/package.dhall sha256:b8d20ab3216083622ae371fb42a6732bc67bb2d66e84989c8ddba7556a336cf7
     ? ./Double/package.dhall
 , Function =
       ./Function/package.dhall sha256:74c3822b98b9d37f9f820af8e1a7ee790bcfac03050eabd45af4a255fb93e026
     ? ./Function/package.dhall
-, `Integer` =
+, Integer =
       ./Integer/package.dhall sha256:eb464566d3192dd16ce915a9bd874aaaad612d5c69beb356e5b7d2e0c4949dcf
     ? ./Integer/package.dhall
-, `List` =
+, List =
       ./List/package.dhall sha256:108be3af5ebd465f7091039f2216c433e65ae5d25556a9a71786dd84d33ef49a
     ? ./List/package.dhall
-, `Natural` =
+, Natural =
       ./Natural/package.dhall sha256:fe08155c3a04500df847ca94d013ecd3dfc73ab5c136109b2414fce3ec42b63a
     ? ./Natural/package.dhall
-, `Optional` =
+, Optional =
       ./Optional/package.dhall sha256:36a366af67a3c26cd5d196e095d3023f18953c5b5db3a03956fa554609e5442a
     ? ./Optional/package.dhall
 , JSON =
       ./JSON/package.dhall sha256:7f0c25a292e5d34ddfbbf3f6d90505567382f95d822b04f5810745f81ab1ef35
     ? ./JSON/package.dhall
-, `Text` =
+, Text =
       ./Text/package.dhall sha256:c8bc93456397476051dc674c180ddd5db098546861c8df24bda8284511d3305e
     ? ./Text/package.dhall
 }
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreA.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreA.dhall
@@ -0,0 +1,1 @@
+λ(_ : A) → b
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreB.dhall
@@ -0,0 +1,1 @@
+λ(_ : A) → b
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXA.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXA.dhall
@@ -0,0 +1,1 @@
+λ(x : A) → x
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXB.dhall
@@ -0,0 +1,1 @@
+λ(_ : A) → _
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXA.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXA.dhall
@@ -0,0 +1,1 @@
+λ(x : A) → λ(_ : B) → x
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXB.dhall
@@ -0,0 +1,1 @@
+λ(_ : A) → λ(_ : B) → _@1
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXA.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXA.dhall
@@ -0,0 +1,1 @@
+\(x: Bool) -> \(x: Bool) -> x && x@1
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXB.dhall
@@ -0,0 +1,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
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXFreeA.dhall
@@ -0,0 +1,1 @@
+\(x: Bool) -> \(x: Bool) -> [x, x@0, x@1, x@2, x@3]
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXFreeB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXFreeB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXFreeB.dhall
@@ -0,0 +1,1 @@
+\(_: Bool) -> \(_: Bool) -> [_, _, _@1, x, x@1]
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXYA.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXYA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXYA.dhall
@@ -0,0 +1,1 @@
+\(x: Bool) -> \(y: Bool) -> x && y
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXYB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXYB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXYB.dhall
@@ -0,0 +1,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
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingUnderscoreA.dhall
@@ -0,0 +1,1 @@
+A → B
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingUnderscoreB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingUnderscoreB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingUnderscoreB.dhall
@@ -0,0 +1,1 @@
+A → B
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXA.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXA.dhall
@@ -0,0 +1,1 @@
+∀(x : A) → x
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXB.dhall
@@ -0,0 +1,1 @@
+A → _
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXA.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXA.dhall
@@ -0,0 +1,1 @@
+∀(x : A) → B → x
diff --git a/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXB.dhall b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXB.dhall
@@ -0,0 +1,1 @@
+A → B → _@1
diff --git a/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORX2A.dhallb b/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORX2A.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORX2A.dhallb differ
diff --git a/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORX2B.dhall b/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORX2B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORX2B.dhall
@@ -0,0 +1,1 @@
+x
diff --git a/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORX3A.dhallb b/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORX3A.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORX3A.dhallb differ
diff --git a/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORX3B.dhall b/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORX3B.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORX3B.dhall
@@ -0,0 +1,1 @@
+x
diff --git a/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORXA.dhallb b/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORXA.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORXA.dhallb differ
diff --git a/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORXB.dhall b/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORXB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/binary-decode/success/unit/SelfDescribeCBORXB.dhall
@@ -0,0 +1,1 @@
+x
diff --git a/dhall-lang/tests/import/data/simple.dhall b/dhall-lang/tests/import/data/simple.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/import/data/simple.dhall
@@ -0,0 +1,1 @@
+3
diff --git a/dhall-lang/tests/import/failure/hashMismatch.dhall b/dhall-lang/tests/import/failure/hashMismatch.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/import/failure/hashMismatch.dhall
@@ -0,0 +1,1 @@
+../data/simple.dhall sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/dhall-lang/tests/import/success/alternativeHashMismatchA.dhall b/dhall-lang/tests/import/success/alternativeHashMismatchA.dhall
--- a/dhall-lang/tests/import/success/alternativeHashMismatchA.dhall
+++ b/dhall-lang/tests/import/success/alternativeHashMismatchA.dhall
@@ -1,1 +1,2 @@
-(./alternativeHashMismatchB.dhall sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) ? 42
+  ../data/simple.dhall sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+? 42
diff --git a/dhall-lang/tests/import/success/customHeadersA.dhall b/dhall-lang/tests/import/success/customHeadersA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/import/success/customHeadersA.dhall
@@ -0,0 +1,3 @@
+https://httpbin.org/user-agent
+  using [ { header = "User-Agent", value = "Dhall" } ]
+  as Text
diff --git a/dhall-lang/tests/import/success/customHeadersB.dhall b/dhall-lang/tests/import/success/customHeadersB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/import/success/customHeadersB.dhall
@@ -0,0 +1,5 @@
+''
+{
+  "user-agent": "Dhall"
+}
+''
diff --git a/dhall-lang/tests/import/success/headerForwardingA.dhall b/dhall-lang/tests/import/success/headerForwardingA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/import/success/headerForwardingA.dhall
@@ -0,0 +1,16 @@
+{- This test verifies that header-forwarding works correctly for relative
+   imports within the same domain
+
+   `test.dhall-lang.org` is the same as `prelude.dhall-lang.org` except that
+   `test.dhall-lang.org` rejects all requests without a `Test` header.
+
+   This test requires that the initial import to
+   `https://test.dhall-lang.org/Bool/package.dhall` forwards the `Test` header
+   to the transitive relative imports of `https://test.dhall-lang.org/Bool/*` in
+   order to succeed.
+
+   Note: You will need to update this test whenever the `Bool` package in the
+   Prelude changes (sorry)
+-}
+https://test.dhall-lang.org/Bool/package.dhall
+  using [ { header = "Test", value = "Example" } ]
diff --git a/dhall-lang/tests/import/success/headerForwardingB.dhall b/dhall-lang/tests/import/success/headerForwardingB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/import/success/headerForwardingB.dhall
@@ -0,0 +1,26 @@
+{ and =
+      λ(xs : List Bool)
+    → List/fold Bool xs Bool (λ(l : Bool) → λ(r : Bool) → l && r) True
+, build =
+      λ(f : ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool)
+    → f Bool True False
+, even =
+      λ(xs : List Bool)
+    → List/fold Bool xs Bool (λ(x : Bool) → λ(y : Bool) → x == y) True
+, fold =
+      λ(b : Bool)
+    → λ(bool : Type)
+    → λ(true : bool)
+    → λ(false : bool)
+    → if b then true else false
+, not =
+    λ(b : Bool) → b == False
+, odd =
+      λ(xs : List Bool)
+    → List/fold Bool xs Bool (λ(x : Bool) → λ(y : Bool) → x != y) False
+, or =
+      λ(xs : List Bool)
+    → List/fold Bool xs Bool (λ(l : Bool) → λ(r : Bool) → l || r) False
+, show =
+    λ(b : Bool) → if b then "True" else "False"
+}
diff --git a/dhall-lang/tests/import/success/noHeaderForwardingA.dhall b/dhall-lang/tests/import/success/noHeaderForwardingA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/import/success/noHeaderForwardingA.dhall
@@ -0,0 +1,6 @@
+{- The purpose of this test is to verify that the custom headers supplied to
+   this import are not forwarded to the transitive import of
+   https://httpbin.org/user-agent
+-}
+https://raw.githubusercontent.com/dhall-lang/dhall-lang/master/tests/import/success/customHeadersA.dhall
+  using [ { header = "User-Agent", value = "Secret" } ]
diff --git a/dhall-lang/tests/import/success/noHeaderForwardingB.dhall b/dhall-lang/tests/import/success/noHeaderForwardingB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/import/success/noHeaderForwardingB.dhall
@@ -0,0 +1,5 @@
+''
+{
+  "user-agent": "Dhall"
+}
+''
diff --git a/dhall-lang/tests/normalization/success/simple/letAvoidCaptureA.dhall b/dhall-lang/tests/normalization/success/simple/letAvoidCaptureA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/simple/letAvoidCaptureA.dhall
@@ -0,0 +1,3 @@
+\(x: Natural)
+-> let var = x
+   in \(x: Bool) -> var
diff --git a/dhall-lang/tests/normalization/success/simple/letAvoidCaptureB.dhall b/dhall-lang/tests/normalization/success/simple/letAvoidCaptureB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/simple/letAvoidCaptureB.dhall
@@ -0,0 +1,1 @@
+λ(x : Natural) → λ(x : Bool) → x@1
diff --git a/dhall-lang/tests/normalization/success/simple/letenumA.dhall b/dhall-lang/tests/normalization/success/simple/letenumA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/simple/letenumA.dhall
@@ -0,0 +1,3 @@
+let enum = < x >.x
+in
+merge { x = 1 } enum
diff --git a/dhall-lang/tests/normalization/success/simple/letenumB.dhall b/dhall-lang/tests/normalization/success/simple/letenumB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/simple/letenumB.dhall
@@ -0,0 +1,1 @@
+1
diff --git a/dhall-lang/tests/normalization/success/simple/naturalPlusA.dhall b/dhall-lang/tests/normalization/success/simple/naturalPlusA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/simple/naturalPlusA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-1 + 2
diff --git a/dhall-lang/tests/normalization/success/simple/naturalPlusB.dhall b/dhall-lang/tests/normalization/success/simple/naturalPlusB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/simple/naturalPlusB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-3
diff --git a/dhall-lang/tests/normalization/success/simple/naturalShowA.dhall b/dhall-lang/tests/normalization/success/simple/naturalShowA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/simple/naturalShowA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-Natural/show 42
diff --git a/dhall-lang/tests/normalization/success/simple/naturalShowB.dhall b/dhall-lang/tests/normalization/success/simple/naturalShowB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/simple/naturalShowB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-"42"
diff --git a/dhall-lang/tests/normalization/success/simple/naturalToIntegerA.dhall b/dhall-lang/tests/normalization/success/simple/naturalToIntegerA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/simple/naturalToIntegerA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-Natural/toInteger 1
diff --git a/dhall-lang/tests/normalization/success/simple/naturalToIntegerB.dhall b/dhall-lang/tests/normalization/success/simple/naturalToIntegerB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/simple/naturalToIntegerB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-+1
diff --git a/dhall-lang/tests/normalization/success/simple/optionalBuildFoldA.dhall b/dhall-lang/tests/normalization/success/simple/optionalBuildFoldA.dhall
--- a/dhall-lang/tests/normalization/success/simple/optionalBuildFoldA.dhall
+++ b/dhall-lang/tests/normalization/success/simple/optionalBuildFoldA.dhall
@@ -1,1 +1,1 @@
-Optional/build Text (Optional/fold Text ([ "foo" ] : Optional Text))
+Optional/build Text (Optional/fold Text (Some "foo"))
diff --git a/dhall-lang/tests/normalization/success/simple/optionalFoldA.dhall b/dhall-lang/tests/normalization/success/simple/optionalFoldA.dhall
--- a/dhall-lang/tests/normalization/success/simple/optionalFoldA.dhall
+++ b/dhall-lang/tests/normalization/success/simple/optionalFoldA.dhall
@@ -2,6 +2,6 @@
             λ(o : Optional Text)
           → Optional/fold Text o Natural (λ(j : Text) → 1) 2
 
-in  { example0 = f ([ "foo" ] : Optional Text)
-    , example1 = f ([] : Optional Text)
+in  { example0 = f (Some "foo")
+    , example1 = f (None Text)
     }
diff --git a/dhall-lang/tests/normalization/success/simple/simpleAdditionA.dhall b/dhall-lang/tests/normalization/success/simple/simpleAdditionA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/simple/simpleAdditionA.dhall
@@ -0,0 +1,1 @@
+(\(x: Natural) -> x + 1) 0
diff --git a/dhall-lang/tests/normalization/success/simple/simpleAdditionB.dhall b/dhall-lang/tests/normalization/success/simple/simpleAdditionB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/simple/simpleAdditionB.dhall
@@ -0,0 +1,1 @@
+1
diff --git a/dhall-lang/tests/normalization/success/unit/BareInterpolationA.dhall b/dhall-lang/tests/normalization/success/unit/BareInterpolationA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/BareInterpolationA.dhall
@@ -0,0 +1,1 @@
+"${x}"
diff --git a/dhall-lang/tests/normalization/success/unit/BareInterpolationB.dhall b/dhall-lang/tests/normalization/success/unit/BareInterpolationB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/BareInterpolationB.dhall
@@ -0,0 +1,1 @@
+x
diff --git a/dhall-lang/tests/normalization/success/unit/ListHeadOneA.dhall b/dhall-lang/tests/normalization/success/unit/ListHeadOneA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/ListHeadOneA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-List/head Natural [ 1 ]
diff --git a/dhall-lang/tests/normalization/success/unit/ListHeadOneB.dhall b/dhall-lang/tests/normalization/success/unit/ListHeadOneB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/ListHeadOneB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-Some 1
diff --git a/dhall-lang/tests/normalization/success/unit/ListHeadTwoA.dhall b/dhall-lang/tests/normalization/success/unit/ListHeadTwoA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/ListHeadTwoA.dhall
@@ -0,0 +1,1 @@
+List/head Natural [ 1, 2 ]
diff --git a/dhall-lang/tests/normalization/success/unit/ListHeadTwoB.dhall b/dhall-lang/tests/normalization/success/unit/ListHeadTwoB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/ListHeadTwoB.dhall
@@ -0,0 +1,1 @@
+Some 1
diff --git a/dhall-lang/tests/normalization/success/unit/ListLastOneA.dhall b/dhall-lang/tests/normalization/success/unit/ListLastOneA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/ListLastOneA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-List/last Natural [ 1 ]
diff --git a/dhall-lang/tests/normalization/success/unit/ListLastOneB.dhall b/dhall-lang/tests/normalization/success/unit/ListLastOneB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/ListLastOneB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-Some 1
diff --git a/dhall-lang/tests/normalization/success/unit/ListLastTwoA.dhall b/dhall-lang/tests/normalization/success/unit/ListLastTwoA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/ListLastTwoA.dhall
@@ -0,0 +1,1 @@
+List/last Natural [ 1, 2 ]
diff --git a/dhall-lang/tests/normalization/success/unit/ListLastTwoB.dhall b/dhall-lang/tests/normalization/success/unit/ListLastTwoB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/ListLastTwoB.dhall
@@ -0,0 +1,1 @@
+Some 2
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,1 @@
-merge { x = λ(_ : A) → _ } < x = y > : A
+merge { x = λ(_ : A) → _ } (< x : T >.x y) : A
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) → x) x
+Natural/fold 1 Natural (λ(x : Natural) → 5) 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 @@
-x
+5
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,1 +1,5 @@
-"${x}"
+{- 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
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyA.dhall
@@ -0,0 +1,1 @@
+x ++ ""
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyB.dhall
@@ -0,0 +1,5 @@
+{- 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
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyA.dhall
@@ -0,0 +1,1 @@
+x ++ "hai"
diff --git a/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyB.dhall
@@ -0,0 +1,1 @@
+"${x}hai"
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 ([] : Optional A) B (λ(_ : A) → _) x
+Optional/fold A (None A) B (λ(_ : A) → _) x
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionTypeEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionTypeEmptyA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionTypeEmptyA.dhall
@@ -0,0 +1,1 @@
+{ a = 10, b = Some 10 }.({})
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionTypeEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionTypeEmptyB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionTypeEmptyB.dhall
@@ -0,0 +1,1 @@
+{=}
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionTypeNonEmptyA.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionTypeNonEmptyA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionTypeNonEmptyA.dhall
@@ -0,0 +1,1 @@
+{ a = 10, b = Some 10, c = [ "text" ]}.({ a : Natural, b : Optional Natural })
diff --git a/dhall-lang/tests/normalization/success/unit/RecordProjectionTypeNonEmptyB.dhall b/dhall-lang/tests/normalization/success/unit/RecordProjectionTypeNonEmptyB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/RecordProjectionTypeNonEmptyB.dhall
@@ -0,0 +1,1 @@
+{ a = 10, b = Some 10 }
diff --git a/dhall-lang/tests/normalization/success/unit/TextShowInterpolatedA.dhall b/dhall-lang/tests/normalization/success/unit/TextShowInterpolatedA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/TextShowInterpolatedA.dhall
@@ -0,0 +1,1 @@
+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
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/TextShowInterpolatedB.dhall
@@ -0,0 +1,1 @@
+Text/show "text ${with} interpolation"
diff --git a/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeAlternativesA.dhall b/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeAlternativesA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeAlternativesA.dhall
@@ -0,0 +1,1 @@
+< 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
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeAlternativesB.dhall
@@ -0,0 +1,1 @@
+< 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
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeArgumentsA.dhall
@@ -0,0 +1,1 @@
+< 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
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeArgumentsB.dhall
@@ -0,0 +1,1 @@
+< x = y >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionLiteralSortAlternativesA.dhall b/dhall-lang/tests/normalization/success/unit/UnionLiteralSortAlternativesA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/UnionLiteralSortAlternativesA.dhall
@@ -0,0 +1,1 @@
+< 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
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/normalization/success/unit/UnionLiteralSortAlternativesB.dhall
@@ -0,0 +1,1 @@
+< x = y | y : B | z >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionNormalizeAlternativesA.dhall b/dhall-lang/tests/normalization/success/unit/UnionNormalizeAlternativesA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/UnionNormalizeAlternativesA.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/UnionNormalizeAlternativesB.dhall b/dhall-lang/tests/normalization/success/unit/UnionNormalizeAlternativesB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/UnionNormalizeAlternativesB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x = y | y : X | z >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionNormalizeArgumentsA.dhall b/dhall-lang/tests/normalization/success/unit/UnionNormalizeArgumentsA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/UnionNormalizeArgumentsA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x = if True then y else z >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionNormalizeArgumentsB.dhall b/dhall-lang/tests/normalization/success/unit/UnionNormalizeArgumentsB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/UnionNormalizeArgumentsB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x = y >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionSortAlternativesA.dhall b/dhall-lang/tests/normalization/success/unit/UnionSortAlternativesA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/UnionSortAlternativesA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x = y | z | y : B >
diff --git a/dhall-lang/tests/normalization/success/unit/UnionSortAlternativesB.dhall b/dhall-lang/tests/normalization/success/unit/UnionSortAlternativesB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/normalization/success/unit/UnionSortAlternativesB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< x = y | y : B | z >
diff --git a/dhall-lang/tests/parser/failure/urlWithoutPath.dhall b/dhall-lang/tests/parser/failure/urlWithoutPath.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/failure/urlWithoutPath.dhall
@@ -0,0 +1,2 @@
+-- See issue #205 for why this is not permitted
+http://example.com/
diff --git a/dhall-lang/tests/parser/success/RecordProjectionByType.dhall b/dhall-lang/tests/parser/success/RecordProjectionByType.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/RecordProjectionByType.dhall
@@ -0,0 +1,15 @@
+let example1 = λ(A : Type) → λ(B : Type) → λ(C : { x : A, y : B }) → C.({ x : A }) : { x : A }
+
+let example2 =
+	  λ(A : Type)
+	→ λ(B : Type)
+	→ λ(C : { p : A, q : B })
+	→ C.(let r = { p : A } in r) : { p : A }
+
+let A = Natural
+
+let B = Text
+
+in
+
+(example1 A B { x = 10, y = "Text" }) ∧ (example2 A B { p = 10, q = "Text" }) : { x : A, p : A }
diff --git a/dhall-lang/tests/parser/success/builtinsA.dhall b/dhall-lang/tests/parser/success/builtinsA.dhall
--- a/dhall-lang/tests/parser/success/builtinsA.dhall
+++ b/dhall-lang/tests/parser/success/builtinsA.dhall
@@ -28,4 +28,5 @@
   , field17 = Optional/build
   , field18 = True
   , field19 = False
+  , field20 = None
   }
diff --git a/dhall-lang/tests/parser/success/builtinsB.dhallb b/dhall-lang/tests/parser/success/builtinsB.dhallb
Binary files a/dhall-lang/tests/parser/success/builtinsB.dhallb and b/dhall-lang/tests/parser/success/builtinsB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/collectionImportTypeA.dhall b/dhall-lang/tests/parser/success/collectionImportTypeA.dhall
--- a/dhall-lang/tests/parser/success/collectionImportTypeA.dhall
+++ b/dhall-lang/tests/parser/success/collectionImportTypeA.dhall
@@ -1,3 +1,3 @@
-{ example0 = [] : Optional ./type.dhall
+{ example0 = None ./type.dhall
 , example1 = [] : List ./type.dhall
 }
diff --git a/dhall-lang/tests/parser/success/collectionImportTypeB.dhallb b/dhall-lang/tests/parser/success/collectionImportTypeB.dhallb
Binary files a/dhall-lang/tests/parser/success/collectionImportTypeB.dhallb and b/dhall-lang/tests/parser/success/collectionImportTypeB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/import/asTextA.dhall b/dhall-lang/tests/parser/success/import/asTextA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/import/asTextA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-https://example.com/foo as Text
diff --git a/dhall-lang/tests/parser/success/import/asTextB.dhallb b/dhall-lang/tests/parser/success/import/asTextB.dhallb
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/import/asTextB.dhallb
+++ /dev/null
@@ -1,1 +0,0 @@
-öökexample.comcfooö
diff --git a/dhall-lang/tests/parser/success/import/environmentVariablesA.dhall b/dhall-lang/tests/parser/success/import/environmentVariablesA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/import/environmentVariablesA.dhall
+++ /dev/null
@@ -1,5 +0,0 @@
-[ env:FOO
-
-  -- Yes, this is legal
-, env:"\"\\\a\b\f\n\r\t\v"
-]
diff --git a/dhall-lang/tests/parser/success/import/environmentVariablesB.dhallb b/dhall-lang/tests/parser/success/import/environmentVariablesB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/import/environmentVariablesB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/import/hashA.dhall b/dhall-lang/tests/parser/success/import/hashA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/import/hashA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-./a.dhall sha256:16173e984d35ee3ffd8b6b79167df89480e67d1cd03ea5d0fc93689e4d928e61
diff --git a/dhall-lang/tests/parser/success/import/hashB.dhallb b/dhall-lang/tests/parser/success/import/hashB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/import/hashB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/import/importAltA.dhall b/dhall-lang/tests/parser/success/import/importAltA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/import/importAltA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-env:UNSET1 as Text ? env:UNSET2 ? missing ? env:UNSET3 ? 2
diff --git a/dhall-lang/tests/parser/success/import/importAltB.dhallb b/dhall-lang/tests/parser/success/import/importAltB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/import/importAltB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/import/parenthesizeUsingA.dhall b/dhall-lang/tests/parser/success/import/parenthesizeUsingA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/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/import/parenthesizeUsingB.dhallb b/dhall-lang/tests/parser/success/import/parenthesizeUsingB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/import/parenthesizeUsingB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/import/pathTerminationA.dhall b/dhall-lang/tests/parser/success/import/pathTerminationA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/import/pathTerminationA.dhall
+++ /dev/null
@@ -1,3 +0,0 @@
--- Verify that certain punctuation marks terminate paths correctly
-  λ(x : ./example)
-→ [./example, {bar = <baz = ./example>, qux = ./example}, ./example]
diff --git a/dhall-lang/tests/parser/success/import/pathTerminationB.dhallb b/dhall-lang/tests/parser/success/import/pathTerminationB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/import/pathTerminationB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/import/pathsA.dhall b/dhall-lang/tests/parser/success/import/pathsA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/import/pathsA.dhall
+++ /dev/null
@@ -1,5 +0,0 @@
-[ /absolute/path
-, ./relative/path
-, ~/home/anchored/path
-, /ipfs/QmQ8w5PLcsNz56dMvRtq54vbuPe9cNnCCUXAQp6xLc6Ccx/Prelude
-]
diff --git a/dhall-lang/tests/parser/success/import/pathsB.dhallb b/dhall-lang/tests/parser/success/import/pathsB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/import/pathsB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/import/quotedPathsA.dhall b/dhall-lang/tests/parser/success/import/quotedPathsA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/import/quotedPathsA.dhall
+++ /dev/null
@@ -1,3 +0,0 @@
-{ example0 = /"foo"/bar/"baz qux"
-, example1 = https://example.com/foo/"bar?baz"?qux
-}
diff --git a/dhall-lang/tests/parser/success/import/quotedPathsB.dhallb b/dhall-lang/tests/parser/success/import/quotedPathsB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/import/quotedPathsB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/import/unicodePathsA.dhall b/dhall-lang/tests/parser/success/import/unicodePathsA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/import/unicodePathsA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-./families/"禺.dhall"
diff --git a/dhall-lang/tests/parser/success/import/unicodePathsB.dhallb b/dhall-lang/tests/parser/success/import/unicodePathsB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/import/unicodePathsB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/import/urlsA.dhall b/dhall-lang/tests/parser/success/import/urlsA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/import/urlsA.dhall
+++ /dev/null
@@ -1,14 +0,0 @@
-[ http://example.com/someFile.dhall
-, https://john:doe@example.com:8080/foo/bar?qux=0#xyzzy
-, http://prelude.dhall-lang.org/package.dhall
-, https://ipfs.io/ipfs/QmQ8w5PLcsNz56dMvRtq54vbuPe9cNnCCUXAQp6xLc6Ccx/Prelude
-, https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True
-, https://127.0.0.1/index.dhall
-, https://[::]/index.dhall
-, https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/tutorial.dhall
-, https://example.com/a%20b/c
-, https://example.com/a+b/c
-
-  -- Yes, this is legal
-, https://-._~%2C!$&'()*+,;=:@-._~%2C!$&'()*+,;=:/foo?/-._~%2C!$&'()*+,;=:@/?
-]
diff --git a/dhall-lang/tests/parser/success/import/urlsB.dhallb b/dhall-lang/tests/parser/success/import/urlsB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/import/urlsB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/largeExpressionA.dhall b/dhall-lang/tests/parser/success/largeExpressionA.dhall
--- a/dhall-lang/tests/parser/success/largeExpressionA.dhall
+++ b/dhall-lang/tests/parser/success/largeExpressionA.dhall
@@ -1,254 +1,273 @@
   λ ( xs
     : List
-      { cores             : Natural
-      , host              : Text
-      , key               : Text
-      , mandatoryFeatures : List Text
-      , platforms         :
+      { 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 : {}
+          < 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
+      , speedFactor :
+          Natural
+      , supportedFeatures :
+          List Text
+      , user :
+          Optional Text
       }
     )
 → List/fold
-  { cores             : Natural
-  , host              : Text
-  , key               : Text
-  , mandatoryFeatures : List Text
-  , platforms         :
+  { 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 : {}
+      < 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
+  , speedFactor :
+      Natural
+  , supportedFeatures :
+      List Text
+  , user :
+      Optional Text
   }
   xs
   Text
   (   λ ( x
-        : { cores             : Natural
-          , host              : Text
-          , key               : Text
-          , mandatoryFeatures : List Text
-          , platforms         :
+        : { 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 : {}
+              < 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
+          , 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    =
-                              λ(_ : {})
-                            → < Empty : {} | NonEmpty : 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
-                              )
-                        , NonEmpty =
-                              λ(result : Text)
-                            → < Empty : {} | NonEmpty : 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
-                              )
-                        }
-                        status
-                        : < Empty : {} | NonEmpty : 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
+                      >
                     )
-                   (< 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    =
-                            λ(_ : {}) →
-                            (< Empty : {} | NonEmpty : Text >.NonEmpty element)
-                        , NonEmpty =
-                              λ(result : Text)
-                            → < Empty : {} | NonEmpty : Text >.NonEmpty (
-                                  element ++ "," ++ result
-                              )
+                → λ(status : < Empty | NonEmpty : Text >)
+                → merge
+                  { Empty =
+                      < Empty | NonEmpty : 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"
                         }
-                        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    =
-                            λ(_ : {}) →
-                            < Empty : {} | NonEmpty : Text >.NonEmpty element
-                        , NonEmpty =
-                              λ(result : Text)
-                            → < Empty : {} | NonEmpty : Text >.NonEmpty (
-                                  element ++ "," ++ result
+                        element
+                      )
+                  , NonEmpty =
+                        λ(result : Text)
+                      → < Empty | NonEmpty : 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
                               )
-                        }
-                        status
-                        : < Empty : {} | NonEmpty : Text >
-                    )
-                   (< Empty : {} | NonEmpty : Text >.Empty {=})
-                  )
-                  : Text
-                )
-            ++  "\n"
+                          ++  ","
+                          ++  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 =
+                      < Empty | NonEmpty : Text >.NonEmpty element
+                  , NonEmpty =
+                        λ(result : Text)
+                      → < Empty | NonEmpty : Text >.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 =
+                      < Empty | NonEmpty : Text >.NonEmpty element
+                  , NonEmpty =
+                        λ(result : Text)
+                      → < Empty | NonEmpty : Text >.NonEmpty
+                        (element ++ "," ++ result)
+                  }
+                  status
+                  : < Empty | NonEmpty : Text >
+              )
+              < Empty | NonEmpty : Text >.Empty
+            )
+            : Text
+          )
+      ++  ''
+          
+          ''
       ++  y
   )
   ""
diff --git a/dhall-lang/tests/parser/success/largeExpressionB.dhallb b/dhall-lang/tests/parser/success/largeExpressionB.dhallb
Binary files a/dhall-lang/tests/parser/success/largeExpressionB.dhallb and b/dhall-lang/tests/parser/success/largeExpressionB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/leadingTabsA.dhall b/dhall-lang/tests/parser/success/leadingTabsA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/leadingTabsA.dhall
@@ -0,0 +1,21 @@
+{- This test verifies that leading tabs are correctly stripped
+
+   Since one line is blank and the other line only has tabs, they are all
+   stripped since they all count as leading whitespace for dedenting purposes.
+
+   The end result is that the dedented string is equivalent to:
+
+```
+''
+
+''
+```
+
+   ... which desugars to a single "\n".
+
+   Carefully note that the two spaces before the starting quotes are not
+   counted for dedenting purposes.
+-}
+  ''
+
+		''
diff --git a/dhall-lang/tests/parser/success/leadingTabsB.dhallb b/dhall-lang/tests/parser/success/leadingTabsB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/leadingTabsB.dhallb
@@ -0,0 +1,1 @@
+a
diff --git a/dhall-lang/tests/parser/success/mergeA.dhall b/dhall-lang/tests/parser/success/mergeA.dhall
--- a/dhall-lang/tests/parser/success/mergeA.dhall
+++ b/dhall-lang/tests/parser/success/mergeA.dhall
@@ -1,7 +1,7 @@
   λ(x : <>)
 → { bar = merge {=} x : Integer
   , foo =
-      merge
-      { Left = λ(b : Bool) → b, Right = Natural/even }
-      < Left = True | Right : Natural >
+	  merge
+	  { Left = λ(b : Bool) → b, Right = Natural/even }
+	  (< Left : Bool | Right : Natural >.Left True)
   }
diff --git a/dhall-lang/tests/parser/success/mergeB.dhallb b/dhall-lang/tests/parser/success/mergeB.dhallb
Binary files a/dhall-lang/tests/parser/success/mergeB.dhallb and b/dhall-lang/tests/parser/success/mergeB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/mergeXYZA.dhall b/dhall-lang/tests/parser/success/mergeXYZA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/mergeXYZA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-merge x y z
diff --git a/dhall-lang/tests/parser/success/mergeXYZB.dhallb b/dhall-lang/tests/parser/success/mergeXYZB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/mergeXYZB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/someXYZA.dhall b/dhall-lang/tests/parser/success/someXYZA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/someXYZA.dhall
+++ /dev/null
@@ -1,6 +0,0 @@
-{-
-This is always a type error, but if this
-was a parse error it would be quite confusing
-because Some looks like a builtin.
--}
-Some x y z
diff --git a/dhall-lang/tests/parser/success/someXYZB.dhallb b/dhall-lang/tests/parser/success/someXYZB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/someXYZB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/sortA.dhall b/dhall-lang/tests/parser/success/sortA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/sortA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-Sort
diff --git a/dhall-lang/tests/parser/success/sortB.dhallb b/dhall-lang/tests/parser/success/sortB.dhallb
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/sortB.dhallb
+++ /dev/null
@@ -1,1 +0,0 @@
-dSort
diff --git a/dhall-lang/tests/parser/success/spaceAfterListAppendA.dhall b/dhall-lang/tests/parser/success/spaceAfterListAppendA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/parser/success/spaceAfterListAppendA.dhall
+++ /dev/null
@@ -1,11 +0,0 @@
-{- Fragment identifiers are not allowed in URLs because they serve no purpose
-   for Dhall and they could lead to ambiguity if a parser interprets them as
-   the list append operator (`#`)
-
-   The following expression therefore only has one valid parse, which is to
-   interpret the `#` as a list append.  In other words, the following expression
-   is parsed as:
-
-   (https://example.com/foo) # bar
--}
-https://example.com/foo#bar
diff --git a/dhall-lang/tests/parser/success/spaceAfterListAppendB.dhallb b/dhall-lang/tests/parser/success/spaceAfterListAppendB.dhallb
deleted file mode 100644
Binary files a/dhall-lang/tests/parser/success/spaceAfterListAppendB.dhallb and /dev/null differ
diff --git a/dhall-lang/tests/parser/success/text/multilineBlankLineA.dhall b/dhall-lang/tests/parser/success/text/multilineBlankLineA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/text/multilineBlankLineA.dhall
@@ -0,0 +1,5 @@
+    ''
+    hello
+
+    there
+    ''
diff --git a/dhall-lang/tests/parser/success/text/multilineBlankLineB.dhallb b/dhall-lang/tests/parser/success/text/multilineBlankLineB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/text/multilineBlankLineB.dhallb
@@ -0,0 +1,3 @@
+mhello
+
+there
diff --git a/dhall-lang/tests/parser/success/text/multilineBlankLineCrlfA.dhall b/dhall-lang/tests/parser/success/text/multilineBlankLineCrlfA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/text/multilineBlankLineCrlfA.dhall
@@ -0,0 +1,5 @@
+    ''
+    hello
+
+    there
+    ''
diff --git a/dhall-lang/tests/parser/success/text/multilineBlankLineCrlfB.dhallb b/dhall-lang/tests/parser/success/text/multilineBlankLineCrlfB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/text/multilineBlankLineCrlfB.dhallb
@@ -0,0 +1,3 @@
+mhello
+
+there
diff --git a/dhall-lang/tests/parser/success/text/multilineCorruptedLeadingWhitespaceA.dhall b/dhall-lang/tests/parser/success/text/multilineCorruptedLeadingWhitespaceA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/text/multilineCorruptedLeadingWhitespaceA.dhall
@@ -0,0 +1,5 @@
+	  	''
+	  	hai
+	  	there
+	   ok
+	  	''
diff --git a/dhall-lang/tests/parser/success/text/multilineCorruptedLeadingWhitespaceB.dhallb b/dhall-lang/tests/parser/success/text/multilineCorruptedLeadingWhitespaceB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/text/multilineCorruptedLeadingWhitespaceB.dhallb
@@ -0,0 +1,4 @@
+q	hai
+	there
+ ok
+	
diff --git a/dhall-lang/tests/parser/success/text/multilineIndentedAndAlignedA.dhall b/dhall-lang/tests/parser/success/text/multilineIndentedAndAlignedA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/text/multilineIndentedAndAlignedA.dhall
@@ -0,0 +1,4 @@
+	 ''
+	 hai
+	 there
+	 ''
diff --git a/dhall-lang/tests/parser/success/text/multilineIndentedAndAlignedB.dhallb b/dhall-lang/tests/parser/success/text/multilineIndentedAndAlignedB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/text/multilineIndentedAndAlignedB.dhallb
@@ -0,0 +1,2 @@
+jhai
+there
diff --git a/dhall-lang/tests/parser/success/text/multilineMismatchedLeadingWhitespaceA.dhall b/dhall-lang/tests/parser/success/text/multilineMismatchedLeadingWhitespaceA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/text/multilineMismatchedLeadingWhitespaceA.dhall
@@ -0,0 +1,4 @@
+''
+	a
+ b
+''
diff --git a/dhall-lang/tests/parser/success/text/multilineMismatchedLeadingWhitespaceB.dhallb b/dhall-lang/tests/parser/success/text/multilineMismatchedLeadingWhitespaceB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/text/multilineMismatchedLeadingWhitespaceB.dhallb
@@ -0,0 +1,2 @@
+f	a
+ b
diff --git a/dhall-lang/tests/parser/success/text/multilineTabsA.dhall b/dhall-lang/tests/parser/success/text/multilineTabsA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/text/multilineTabsA.dhall
@@ -0,0 +1,5 @@
+	''
+	hai
+		there
+	   lol
+	''
diff --git a/dhall-lang/tests/parser/success/text/multilineTabsB.dhallb b/dhall-lang/tests/parser/success/text/multilineTabsB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/text/multilineTabsB.dhallb
@@ -0,0 +1,3 @@
+rhai
+	there
+   lol
diff --git a/dhall-lang/tests/parser/success/unit/BoolA.dhall b/dhall-lang/tests/parser/success/unit/BoolA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/BoolA.dhall
@@ -0,0 +1,1 @@
+Bool
diff --git a/dhall-lang/tests/parser/success/unit/BoolB.dhallb b/dhall-lang/tests/parser/success/unit/BoolB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/BoolB.dhallb
@@ -0,0 +1,1 @@
+dBool
diff --git a/dhall-lang/tests/parser/success/unit/BoolLitTrueA.dhall b/dhall-lang/tests/parser/success/unit/BoolLitTrueA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/BoolLitTrueA.dhall
@@ -0,0 +1,1 @@
+True
diff --git a/dhall-lang/tests/parser/success/unit/BoolLitTrueB.dhallb b/dhall-lang/tests/parser/success/unit/BoolLitTrueB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/BoolLitTrueB.dhallb
@@ -0,0 +1,1 @@
+õ
diff --git a/dhall-lang/tests/parser/success/unit/ForallA.dhall b/dhall-lang/tests/parser/success/unit/ForallA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/ForallA.dhall
@@ -0,0 +1,1 @@
+forall(x: T) -> x
diff --git a/dhall-lang/tests/parser/success/unit/ForallB.dhallb b/dhall-lang/tests/parser/success/unit/ForallB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/ForallB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/ForallNestedA.dhall b/dhall-lang/tests/parser/success/unit/ForallNestedA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/ForallNestedA.dhall
@@ -0,0 +1,1 @@
+forall(x: T) -> forall(y: U) -> x
diff --git a/dhall-lang/tests/parser/success/unit/ForallNestedB.dhallb b/dhall-lang/tests/parser/success/unit/ForallNestedB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/ForallNestedB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/ForallUnderscoreA.dhall b/dhall-lang/tests/parser/success/unit/ForallUnderscoreA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/ForallUnderscoreA.dhall
@@ -0,0 +1,1 @@
+forall(_: T) -> x
diff --git a/dhall-lang/tests/parser/success/unit/ForallUnderscoreB.dhallb b/dhall-lang/tests/parser/success/unit/ForallUnderscoreB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/ForallUnderscoreB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/IntegerLitNegativeA.dhall b/dhall-lang/tests/parser/success/unit/IntegerLitNegativeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/IntegerLitNegativeA.dhall
@@ -0,0 +1,1 @@
+-10
diff --git a/dhall-lang/tests/parser/success/unit/IntegerLitNegativeB.dhallb b/dhall-lang/tests/parser/success/unit/IntegerLitNegativeB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/IntegerLitNegativeB.dhallb
@@ -0,0 +1,1 @@
+)
diff --git a/dhall-lang/tests/parser/success/unit/IntegerLitPositiveA.dhall b/dhall-lang/tests/parser/success/unit/IntegerLitPositiveA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/IntegerLitPositiveA.dhall
@@ -0,0 +1,1 @@
++10
diff --git a/dhall-lang/tests/parser/success/unit/IntegerLitPositiveB.dhallb b/dhall-lang/tests/parser/success/unit/IntegerLitPositiveB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/IntegerLitPositiveB.dhallb
@@ -0,0 +1,1 @@
+
diff --git a/dhall-lang/tests/parser/success/unit/KindA.dhall b/dhall-lang/tests/parser/success/unit/KindA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/KindA.dhall
@@ -0,0 +1,1 @@
+Kind
diff --git a/dhall-lang/tests/parser/success/unit/KindB.dhallb b/dhall-lang/tests/parser/success/unit/KindB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/KindB.dhallb
@@ -0,0 +1,1 @@
+dKind
diff --git a/dhall-lang/tests/parser/success/unit/LambdaA.dhall b/dhall-lang/tests/parser/success/unit/LambdaA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/LambdaA.dhall
@@ -0,0 +1,1 @@
+\(x: T) -> x
diff --git a/dhall-lang/tests/parser/success/unit/LambdaB.dhallb b/dhall-lang/tests/parser/success/unit/LambdaB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/LambdaB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/LambdaNestedA.dhall b/dhall-lang/tests/parser/success/unit/LambdaNestedA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/LambdaNestedA.dhall
@@ -0,0 +1,1 @@
+\(x: T) -> \(y: U) -> x
diff --git a/dhall-lang/tests/parser/success/unit/LambdaNestedB.dhallb b/dhall-lang/tests/parser/success/unit/LambdaNestedB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/LambdaNestedB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/LambdaUnderscoreA.dhall b/dhall-lang/tests/parser/success/unit/LambdaUnderscoreA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/LambdaUnderscoreA.dhall
@@ -0,0 +1,1 @@
+\(_: T) -> x
diff --git a/dhall-lang/tests/parser/success/unit/LambdaUnderscoreB.dhallb b/dhall-lang/tests/parser/success/unit/LambdaUnderscoreB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/LambdaUnderscoreB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/ListLitEmptyA.dhall b/dhall-lang/tests/parser/success/unit/ListLitEmptyA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/ListLitEmptyA.dhall
@@ -0,0 +1,1 @@
+[] : List T
diff --git a/dhall-lang/tests/parser/success/unit/ListLitEmptyB.dhallb b/dhall-lang/tests/parser/success/unit/ListLitEmptyB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/ListLitEmptyB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/MergeA.dhall b/dhall-lang/tests/parser/success/unit/MergeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/MergeA.dhall
@@ -0,0 +1,1 @@
+merge x y
diff --git a/dhall-lang/tests/parser/success/unit/MergeAnnotationA.dhall b/dhall-lang/tests/parser/success/unit/MergeAnnotationA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/MergeAnnotationA.dhall
@@ -0,0 +1,1 @@
+merge x y : t
diff --git a/dhall-lang/tests/parser/success/unit/MergeAnnotationB.dhallb b/dhall-lang/tests/parser/success/unit/MergeAnnotationB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/MergeAnnotationB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/MergeAnnotationPrecedenceA.dhall b/dhall-lang/tests/parser/success/unit/MergeAnnotationPrecedenceA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/MergeAnnotationPrecedenceA.dhall
@@ -0,0 +1,1 @@
+merge x y : t a
diff --git a/dhall-lang/tests/parser/success/unit/MergeAnnotationPrecedenceB.dhallb b/dhall-lang/tests/parser/success/unit/MergeAnnotationPrecedenceB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/MergeAnnotationPrecedenceB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/MergeB.dhallb b/dhall-lang/tests/parser/success/unit/MergeB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/MergeB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/MergeParenAnnotationA.dhall b/dhall-lang/tests/parser/success/unit/MergeParenAnnotationA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/MergeParenAnnotationA.dhall
@@ -0,0 +1,1 @@
+(merge x y) : t
diff --git a/dhall-lang/tests/parser/success/unit/MergeParenAnnotationB.dhallb b/dhall-lang/tests/parser/success/unit/MergeParenAnnotationB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/MergeParenAnnotationB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/MergeXYZA.dhall b/dhall-lang/tests/parser/success/unit/MergeXYZA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/MergeXYZA.dhall
@@ -0,0 +1,1 @@
+merge x y z
diff --git a/dhall-lang/tests/parser/success/unit/MergeXYZB.dhallb b/dhall-lang/tests/parser/success/unit/MergeXYZB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/MergeXYZB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/NaturalLitA.dhall b/dhall-lang/tests/parser/success/unit/NaturalLitA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/NaturalLitA.dhall
@@ -0,0 +1,1 @@
+42
diff --git a/dhall-lang/tests/parser/success/unit/NaturalLitB.dhallb b/dhall-lang/tests/parser/success/unit/NaturalLitB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/NaturalLitB.dhallb
@@ -0,0 +1,1 @@
+*
diff --git a/dhall-lang/tests/parser/success/unit/QuotedBoolA.dhall b/dhall-lang/tests/parser/success/unit/QuotedBoolA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/QuotedBoolA.dhall
@@ -0,0 +1,1 @@
+`Bool`
diff --git a/dhall-lang/tests/parser/success/unit/QuotedBoolB.dhallb b/dhall-lang/tests/parser/success/unit/QuotedBoolB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/QuotedBoolB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/QuotedTrueA.dhall b/dhall-lang/tests/parser/success/unit/QuotedTrueA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/QuotedTrueA.dhall
@@ -0,0 +1,1 @@
+`True`
diff --git a/dhall-lang/tests/parser/success/unit/QuotedTrueB.dhallb b/dhall-lang/tests/parser/success/unit/QuotedTrueB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/QuotedTrueB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/QuotedTypeA.dhall b/dhall-lang/tests/parser/success/unit/QuotedTypeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/QuotedTypeA.dhall
@@ -0,0 +1,1 @@
+`Type`
diff --git a/dhall-lang/tests/parser/success/unit/QuotedTypeB.dhallb b/dhall-lang/tests/parser/success/unit/QuotedTypeB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/QuotedTypeB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/QuotedVariableA.dhall b/dhall-lang/tests/parser/success/unit/QuotedVariableA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/QuotedVariableA.dhall
@@ -0,0 +1,1 @@
+`x+y`
diff --git a/dhall-lang/tests/parser/success/unit/QuotedVariableB.dhallb b/dhall-lang/tests/parser/success/unit/QuotedVariableB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/QuotedVariableB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/SomeXA.dhall b/dhall-lang/tests/parser/success/unit/SomeXA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/SomeXA.dhall
@@ -0,0 +1,1 @@
+Some x
diff --git a/dhall-lang/tests/parser/success/unit/SomeXB.dhallb b/dhall-lang/tests/parser/success/unit/SomeXB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/SomeXB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/SomeXYZA.dhall b/dhall-lang/tests/parser/success/unit/SomeXYZA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/SomeXYZA.dhall
@@ -0,0 +1,6 @@
+{-
+This is always a type error, but if this
+was a parse error it would be quite confusing
+because Some looks like a builtin.
+-}
+Some x y z
diff --git a/dhall-lang/tests/parser/success/unit/SomeXYZB.dhallb b/dhall-lang/tests/parser/success/unit/SomeXYZB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/SomeXYZB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/SortA.dhall b/dhall-lang/tests/parser/success/unit/SortA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/SortA.dhall
@@ -0,0 +1,1 @@
+Sort
diff --git a/dhall-lang/tests/parser/success/unit/SortB.dhallb b/dhall-lang/tests/parser/success/unit/SortB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/SortB.dhallb
@@ -0,0 +1,1 @@
+dSort
diff --git a/dhall-lang/tests/parser/success/unit/TypeA.dhall b/dhall-lang/tests/parser/success/unit/TypeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/TypeA.dhall
@@ -0,0 +1,1 @@
+Type
diff --git a/dhall-lang/tests/parser/success/unit/TypeB.dhallb b/dhall-lang/tests/parser/success/unit/TypeB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/TypeB.dhallb
@@ -0,0 +1,1 @@
+dType
diff --git a/dhall-lang/tests/parser/success/unit/UnionLit1A.dhall b/dhall-lang/tests/parser/success/unit/UnionLit1A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/UnionLit1A.dhall
@@ -0,0 +1,1 @@
+< 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
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/UnionLit1B.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/UnionLit2A.dhall b/dhall-lang/tests/parser/success/unit/UnionLit2A.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/UnionLit2A.dhall
@@ -0,0 +1,1 @@
+< 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
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/UnionLit2B.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/UnionTypeEmptyA.dhall b/dhall-lang/tests/parser/success/unit/UnionTypeEmptyA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/UnionTypeEmptyA.dhall
@@ -0,0 +1,1 @@
+< >
diff --git a/dhall-lang/tests/parser/success/unit/UnionTypeEmptyB.dhallb b/dhall-lang/tests/parser/success/unit/UnionTypeEmptyB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/UnionTypeEmptyB.dhallb
@@ -0,0 +1,1 @@
+ 
diff --git a/dhall-lang/tests/parser/success/unit/UnionTypeXA.dhall b/dhall-lang/tests/parser/success/unit/UnionTypeXA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/UnionTypeXA.dhall
@@ -0,0 +1,1 @@
+< x >
diff --git a/dhall-lang/tests/parser/success/unit/UnionTypeXB.dhallb b/dhall-lang/tests/parser/success/unit/UnionTypeXB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/UnionTypeXB.dhallb
@@ -0,0 +1,1 @@
+¡axö
diff --git a/dhall-lang/tests/parser/success/unit/UnionTypeXTYA.dhall b/dhall-lang/tests/parser/success/unit/UnionTypeXTYA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/UnionTypeXTYA.dhall
@@ -0,0 +1,1 @@
+< x: T | y >
diff --git a/dhall-lang/tests/parser/success/unit/UnionTypeXTYB.dhallb b/dhall-lang/tests/parser/success/unit/UnionTypeXTYB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/UnionTypeXTYB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/UnionTypeXTYUA.dhall b/dhall-lang/tests/parser/success/unit/UnionTypeXTYUA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/UnionTypeXTYUA.dhall
@@ -0,0 +1,1 @@
+< x: T | y: U >
diff --git a/dhall-lang/tests/parser/success/unit/UnionTypeXTYUB.dhallb b/dhall-lang/tests/parser/success/unit/UnionTypeXTYUB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/UnionTypeXTYUB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/UnionTypeXYA.dhall b/dhall-lang/tests/parser/success/unit/UnionTypeXYA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/UnionTypeXYA.dhall
@@ -0,0 +1,1 @@
+< x | y >
diff --git a/dhall-lang/tests/parser/success/unit/UnionTypeXYB.dhallb b/dhall-lang/tests/parser/success/unit/UnionTypeXYB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/UnionTypeXYB.dhallb
@@ -0,0 +1,1 @@
+¢axöayö
diff --git a/dhall-lang/tests/parser/success/unit/UnionTypeXYTA.dhall b/dhall-lang/tests/parser/success/unit/UnionTypeXYTA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/UnionTypeXYTA.dhall
@@ -0,0 +1,1 @@
+< x | y: T >
diff --git a/dhall-lang/tests/parser/success/unit/UnionTypeXYTB.dhallb b/dhall-lang/tests/parser/success/unit/UnionTypeXYTB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/UnionTypeXYTB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/VariableA.dhall b/dhall-lang/tests/parser/success/unit/VariableA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/VariableA.dhall
@@ -0,0 +1,1 @@
+x
diff --git a/dhall-lang/tests/parser/success/unit/VariableB.dhallb b/dhall-lang/tests/parser/success/unit/VariableB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/VariableB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/VariableUnderscoreA.dhall b/dhall-lang/tests/parser/success/unit/VariableUnderscoreA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/VariableUnderscoreA.dhall
@@ -0,0 +1,1 @@
+_
diff --git a/dhall-lang/tests/parser/success/unit/VariableUnderscoreB.dhallb b/dhall-lang/tests/parser/success/unit/VariableUnderscoreB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/VariableUnderscoreB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/asTextA.dhall b/dhall-lang/tests/parser/success/unit/import/asTextA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/asTextA.dhall
@@ -0,0 +1,1 @@
+https://example.com/foo as Text
diff --git a/dhall-lang/tests/parser/success/unit/import/asTextB.dhallb b/dhall-lang/tests/parser/success/unit/import/asTextB.dhallb
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/asTextB.dhallb
@@ -0,0 +1,1 @@
+öökexample.comcfooö
diff --git a/dhall-lang/tests/parser/success/unit/import/environmentVariableBashA.dhall b/dhall-lang/tests/parser/success/unit/import/environmentVariableBashA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/environmentVariableBashA.dhall
@@ -0,0 +1,1 @@
+env:FOO
diff --git a/dhall-lang/tests/parser/success/unit/import/environmentVariableBashB.dhallb b/dhall-lang/tests/parser/success/unit/import/environmentVariableBashB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/environmentVariableBashB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/environmentVariablePosixA.dhall b/dhall-lang/tests/parser/success/unit/import/environmentVariablePosixA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/environmentVariablePosixA.dhall
@@ -0,0 +1,2 @@
+-- Yes, this is legal
+env:"\"\\\a\b\f\n\r\t\v"
diff --git a/dhall-lang/tests/parser/success/unit/import/environmentVariablePosixB.dhallb b/dhall-lang/tests/parser/success/unit/import/environmentVariablePosixB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/environmentVariablePosixB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/hashA.dhall b/dhall-lang/tests/parser/success/unit/import/hashA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/hashA.dhall
@@ -0,0 +1,1 @@
+./a.dhall sha256:16173e984d35ee3ffd8b6b79167df89480e67d1cd03ea5d0fc93689e4d928e61
diff --git a/dhall-lang/tests/parser/success/unit/import/hashB.dhallb b/dhall-lang/tests/parser/success/unit/import/hashB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/hashB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/importAltA.dhall b/dhall-lang/tests/parser/success/unit/import/importAltA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/importAltA.dhall
@@ -0,0 +1,1 @@
+env:UNSET1 as Text ? env:UNSET2 ? missing ? env:UNSET3 ? 2
diff --git a/dhall-lang/tests/parser/success/unit/import/importAltB.dhallb b/dhall-lang/tests/parser/success/unit/import/importAltB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/importAltB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/inlineUsingA.dhall b/dhall-lang/tests/parser/success/unit/import/inlineUsingA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/inlineUsingA.dhall
@@ -0,0 +1,14 @@
+{- The language standard used to require that custom headers were provided via
+   an external import, but was later amended to support inline headers as part
+   of:
+
+   https://github.com/dhall-lang/dhall-lang/pull/560
+
+   This test verifies that an implementation supports such inline custom headers
+-}
+
+https://example.com/foo using
+    [ { header = "Authorization"
+      , value  = "token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4"
+      }
+    ]
diff --git a/dhall-lang/tests/parser/success/unit/import/inlineUsingB.dhallb b/dhall-lang/tests/parser/success/unit/import/inlineUsingB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/inlineUsingB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/parenthesizeUsingA.dhall b/dhall-lang/tests/parser/success/unit/import/parenthesizeUsingA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/parenthesizeUsingA.dhall
@@ -0,0 +1,1 @@
+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
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/parenthesizeUsingB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/pathAbsoluteA.dhall b/dhall-lang/tests/parser/success/unit/import/pathAbsoluteA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/pathAbsoluteA.dhall
@@ -0,0 +1,1 @@
+/absolute/path
diff --git a/dhall-lang/tests/parser/success/unit/import/pathAbsoluteB.dhallb b/dhall-lang/tests/parser/success/unit/import/pathAbsoluteB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/pathAbsoluteB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/pathHereA.dhall b/dhall-lang/tests/parser/success/unit/import/pathHereA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/pathHereA.dhall
@@ -0,0 +1,1 @@
+./relative/path
diff --git a/dhall-lang/tests/parser/success/unit/import/pathHereB.dhallb b/dhall-lang/tests/parser/success/unit/import/pathHereB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/pathHereB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/pathHomeA.dhall b/dhall-lang/tests/parser/success/unit/import/pathHomeA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/pathHomeA.dhall
@@ -0,0 +1,1 @@
+~/home/anchored/path
diff --git a/dhall-lang/tests/parser/success/unit/import/pathHomeB.dhallb b/dhall-lang/tests/parser/success/unit/import/pathHomeB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/pathHomeB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/pathParentA.dhall b/dhall-lang/tests/parser/success/unit/import/pathParentA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/pathParentA.dhall
@@ -0,0 +1,1 @@
+../parent/path
diff --git a/dhall-lang/tests/parser/success/unit/import/pathParentB.dhallb b/dhall-lang/tests/parser/success/unit/import/pathParentB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/pathParentB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/pathTerminationLambdaA.dhall b/dhall-lang/tests/parser/success/unit/import/pathTerminationLambdaA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/pathTerminationLambdaA.dhall
@@ -0,0 +1,2 @@
+-- Verify that certain punctuation marks terminate paths correctly
+λ(x : ./example) -> x
diff --git a/dhall-lang/tests/parser/success/unit/import/pathTerminationLambdaB.dhallb b/dhall-lang/tests/parser/success/unit/import/pathTerminationLambdaB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/pathTerminationLambdaB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/pathTerminationListA.dhall b/dhall-lang/tests/parser/success/unit/import/pathTerminationListA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/pathTerminationListA.dhall
@@ -0,0 +1,2 @@
+-- Verify that certain punctuation marks terminate paths correctly
+[./example,./example, ./example]
diff --git a/dhall-lang/tests/parser/success/unit/import/pathTerminationListB.dhallb b/dhall-lang/tests/parser/success/unit/import/pathTerminationListB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/pathTerminationListB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/pathTerminationRecordA.dhall b/dhall-lang/tests/parser/success/unit/import/pathTerminationRecordA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/pathTerminationRecordA.dhall
@@ -0,0 +1,2 @@
+-- Verify that certain punctuation marks terminate paths correctly
+{foo = ./example, bar = ./example}
diff --git a/dhall-lang/tests/parser/success/unit/import/pathTerminationRecordB.dhallb b/dhall-lang/tests/parser/success/unit/import/pathTerminationRecordB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/pathTerminationRecordB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/pathTerminationUnionA.dhall b/dhall-lang/tests/parser/success/unit/import/pathTerminationUnionA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/pathTerminationUnionA.dhall
@@ -0,0 +1,2 @@
+-- Verify that certain punctuation marks terminate paths correctly
+<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
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/pathTerminationUnionB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/quotedPathsA.dhall b/dhall-lang/tests/parser/success/unit/import/quotedPathsA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/quotedPathsA.dhall
@@ -0,0 +1,3 @@
+{ example0 = /"foo"/bar/"baz qux"
+, example1 = https://example.com/foo/"bar?baz"?qux
+}
diff --git a/dhall-lang/tests/parser/success/unit/import/quotedPathsB.dhallb b/dhall-lang/tests/parser/success/unit/import/quotedPathsB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/quotedPathsB.dhallb differ
diff --git a/dhall-lang/tests/parser/success/unit/import/unicodePathsA.dhall b/dhall-lang/tests/parser/success/unit/import/unicodePathsA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/parser/success/unit/import/unicodePathsA.dhall
@@ -0,0 +1,1 @@
+./families/"禺.dhall"
diff --git a/dhall-lang/tests/parser/success/unit/import/unicodePathsB.dhallb b/dhall-lang/tests/parser/success/unit/import/unicodePathsB.dhallb
new file mode 100644
Binary files /dev/null and b/dhall-lang/tests/parser/success/unit/import/unicodePathsB.dhallb differ
diff --git a/dhall-lang/tests/typecheck/data/importBoundary.dhall b/dhall-lang/tests/typecheck/data/importBoundary.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/data/importBoundary.dhall
@@ -0,0 +1,3 @@
+-- This file contains a free variable. This should be a type error, even if the variable
+-- is in scope in the importing expression
+x
diff --git a/dhall-lang/tests/typecheck/failure/customHeadersUsingBoundVariable.dhall b/dhall-lang/tests/typecheck/failure/customHeadersUsingBoundVariable.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/failure/customHeadersUsingBoundVariable.dhall
@@ -0,0 +1,15 @@
+{- This is a type error because the custom headers are type-checked with an
+   empty context.  This is necessary because:
+
+   * import resolution precedes β-normalization
+   * we also don't want custom headers to leak program state anyway
+
+   This should fail due to the `x` within the custom header being an unbound
+   variable
+-}
+
+let x = "Bar"
+
+in https://httpbin.org/headers
+     using [ { header = "Foo", value = x } ]
+     as Text
diff --git a/dhall-lang/tests/typecheck/failure/importBoundary.dhall b/dhall-lang/tests/typecheck/failure/importBoundary.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/failure/importBoundary.dhall
@@ -0,0 +1,1 @@
+\(x: Bool) -> ../data/importBoundary.dhall
diff --git a/dhall-lang/tests/typecheck/success/recordOfRecordOfTypesA.dhall b/dhall-lang/tests/typecheck/success/recordOfRecordOfTypesA.dhall
--- a/dhall-lang/tests/typecheck/success/recordOfRecordOfTypesA.dhall
+++ b/dhall-lang/tests/typecheck/success/recordOfRecordOfTypesA.dhall
@@ -1,3 +1,5 @@
-let types = { Scopes = < Public : {} | Private : {} >}
+let types = { Scopes = < Public | Private > }
+
 let prelude = { types = types }
-in  prelude.types.Scopes.Public {=}
+
+in  prelude.types.Scopes.Public
diff --git a/dhall-lang/tests/typecheck/success/recordOfRecordOfTypesB.dhall b/dhall-lang/tests/typecheck/success/recordOfRecordOfTypesB.dhall
--- a/dhall-lang/tests/typecheck/success/recordOfRecordOfTypesB.dhall
+++ b/dhall-lang/tests/typecheck/success/recordOfRecordOfTypesB.dhall
@@ -1,1 +1,1 @@
-< Public : {} | Private : {} >
+< Public | Private >
diff --git a/dhall-lang/tests/typecheck/success/simple/alternativesAreTypesA.dhall b/dhall-lang/tests/typecheck/success/simple/alternativesAreTypesA.dhall
deleted file mode 100644
--- a/dhall-lang/tests/typecheck/success/simple/alternativesAreTypesA.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< Left = List | Right : Type >
diff --git a/dhall-lang/tests/typecheck/success/simple/alternativesAreTypesB.dhall b/dhall-lang/tests/typecheck/success/simple/alternativesAreTypesB.dhall
deleted file mode 100644
--- a/dhall-lang/tests/typecheck/success/simple/alternativesAreTypesB.dhall
+++ /dev/null
@@ -1,1 +0,0 @@
-< Left : Type → Type | Right : Type >
diff --git a/dhall-lang/tests/typecheck/success/simple/complexShadowingA.dhall b/dhall-lang/tests/typecheck/success/simple/complexShadowingA.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/simple/complexShadowingA.dhall
@@ -0,0 +1,6 @@
+let x = Bool
+let x = Natural
+in  \(x: x@1 {- Bool -})
+ -> \(x: x@1 {- Natural -})
+ -> let x = if x@1 then 0 else 1
+    in  (x + x@1) : x@3
diff --git a/dhall-lang/tests/typecheck/success/simple/complexShadowingB.dhall b/dhall-lang/tests/typecheck/success/simple/complexShadowingB.dhall
new file mode 100644
--- /dev/null
+++ b/dhall-lang/tests/typecheck/success/simple/complexShadowingB.dhall
@@ -0,0 +1,1 @@
+∀(x : Bool) → ∀(x : Natural) → Natural
diff --git a/dhall-lang/tests/typecheck/success/simple/mergeEquivalenceA.dhall b/dhall-lang/tests/typecheck/success/simple/mergeEquivalenceA.dhall
--- a/dhall-lang/tests/typecheck/success/simple/mergeEquivalenceA.dhall
+++ b/dhall-lang/tests/typecheck/success/simple/mergeEquivalenceA.dhall
@@ -1,6 +1,6 @@
-    let Foo = < Bar : {} | Baz : {} >
+let Foo = < Bar : Natural | Baz : Natural >
 
 in    λ(a : Type)
-    → λ(f : {} → a)
-    → λ(ts : Foo)
-    → merge { Bar = λ(a : {}) → f a, Baz = f } ts
+	→ λ(f : Natural → a)
+	→ λ(ts : Foo)
+	→ merge { Bar = λ(a : Natural) → f a, Baz = f } ts
diff --git a/dhall-lang/tests/typecheck/success/simple/mergeEquivalenceB.dhall b/dhall-lang/tests/typecheck/success/simple/mergeEquivalenceB.dhall
--- a/dhall-lang/tests/typecheck/success/simple/mergeEquivalenceB.dhall
+++ b/dhall-lang/tests/typecheck/success/simple/mergeEquivalenceB.dhall
@@ -1,1 +1,1 @@
-∀(a : Type) → ∀(f : {} → a) → ∀(ts : < Bar : {} | Baz : {} >) → a
+∀(a : Type) → ∀(f : Natural → a) → ∀(ts : < Bar : Natural | Baz : Natural >) → a
diff --git a/dhall-lang/tests/typecheck/success/simple/mixedFieldAccessA.dhall b/dhall-lang/tests/typecheck/success/simple/mixedFieldAccessA.dhall
--- a/dhall-lang/tests/typecheck/success/simple/mixedFieldAccessA.dhall
+++ b/dhall-lang/tests/typecheck/success/simple/mixedFieldAccessA.dhall
@@ -2,6 +2,8 @@
 -- constructor within the same expression.  This is a common idiom if a user
 -- provides a types package.
 
-let Scope = < Public : {} | Private : {} >
+let Scope = < Public | Private >
+
 let types = { Scope = Scope }
-in types.Scope.Public {=}
+
+in  types.Scope.Public
diff --git a/dhall-lang/tests/typecheck/success/simple/mixedFieldAccessB.dhall b/dhall-lang/tests/typecheck/success/simple/mixedFieldAccessB.dhall
--- a/dhall-lang/tests/typecheck/success/simple/mixedFieldAccessB.dhall
+++ b/dhall-lang/tests/typecheck/success/simple/mixedFieldAccessB.dhall
@@ -1,1 +1,1 @@
-< Private : {} | Public : {} >
+< Private | Public >
diff --git a/dhall-lang/tests/typecheck/success/simple/unionsOfTypesA.dhall b/dhall-lang/tests/typecheck/success/simple/unionsOfTypesA.dhall
--- a/dhall-lang/tests/typecheck/success/simple/unionsOfTypesA.dhall
+++ b/dhall-lang/tests/typecheck/success/simple/unionsOfTypesA.dhall
@@ -1,1 +1,1 @@
-< Left = List | Right : Type >
+< Left : Type → Type | Right : Type >.Left List
diff --git a/dhall.cabal b/dhall.cabal
--- a/dhall.cabal
+++ b/dhall.cabal
@@ -1,6 +1,6 @@
 Name: dhall
-Version: 1.23.0
-cabal-Version: >=1.10
+Version: 1.24.0
+Cabal-Version: >=1.10
 Build-Type: Simple
 Tested-With: GHC == 7.10.3, GHC == 8.4.3, GHC == 8.6.1
 License: BSD3
@@ -102,6 +102,8 @@
     dhall-lang/Prelude/Text/concatSep
     dhall-lang/Prelude/Text/package.dhall
     dhall-lang/Prelude/Text/show
+    dhall-lang/tests/binary-decode/success/unit/*.dhall
+    dhall-lang/tests/binary-decode/success/unit/*.dhallb
     dhall-lang/tests/import/data/*.txt
     dhall-lang/tests/import/data/*.dhall
     dhall-lang/tests/import/data/fieldOrder/*.dhall
@@ -233,13 +235,17 @@
     dhall-lang/tests/normalization/success/simple/*.dhall
     dhall-lang/tests/normalization/success/simplifications/*.dhall
     dhall-lang/tests/normalization/success/unit/*.dhall
+    dhall-lang/tests/alpha-normalization/success/unit/*.dhall
     dhall-lang/tests/parser/failure/*.dhall
     dhall-lang/tests/parser/success/*.dhall
     dhall-lang/tests/parser/success/*.dhallb
-    dhall-lang/tests/parser/success/import/*.dhall
-    dhall-lang/tests/parser/success/import/*.dhallb
+    dhall-lang/tests/parser/success/unit/*.dhall
+    dhall-lang/tests/parser/success/unit/*.dhallb
+    dhall-lang/tests/parser/success/unit/import/*.dhall
+    dhall-lang/tests/parser/success/unit/import/*.dhallb
     dhall-lang/tests/parser/success/text/*.dhall
     dhall-lang/tests/parser/success/text/*.dhallb
+    dhall-lang/tests/typecheck/data/*.dhall
     dhall-lang/tests/typecheck/failure/*.dhall
     dhall-lang/tests/typecheck/success/*.dhall
     dhall-lang/tests/typecheck/success/prelude/Bool/and/*.dhall
@@ -408,6 +414,7 @@
         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 ,
         repline                     >= 0.2.1.0  && < 0.3 ,
         serialise                   >= 0.2.0.0  && < 0.3 ,
         scientific                  >= 0.3.0.0  && < 0.4 ,
@@ -471,7 +478,9 @@
         Dhall.Lint,
         Dhall.Main,
         Dhall.Map,
+        Dhall.Optics,
         Dhall.Set,
+        Dhall.Src,
         Dhall.Parser,
         Dhall.Pretty,
         Dhall.Repl,
@@ -530,6 +539,7 @@
         directory                                      ,
         filepath                                       ,
         foldl                                    < 1.5 ,
+        megaparsec                                     ,
         prettyprinter                                  ,
         QuickCheck                >= 2.10     && < 2.14,
         quickcheck-instances      >= 0.3.12   && < 0.4 ,
diff --git a/src/Dhall/Binary.hs b/src/Dhall/Binary.hs
--- a/src/Dhall/Binary.hs
+++ b/src/Dhall/Binary.hs
@@ -43,7 +43,6 @@
     , Var(..)
     )
 
-import Data.ByteArray.Encoding (Base(..))
 import Data.Foldable (toList)
 import Data.List.NonEmpty (NonEmpty(..))
 import Data.Monoid ((<>))
@@ -53,11 +52,9 @@
 import GHC.Float (double2Float, float2Double)
 
 import qualified Crypto.Hash
-import qualified Data.ByteArray.Encoding
+import qualified Data.ByteArray
 import qualified Data.ByteString
 import qualified Data.Sequence
-import qualified Data.Text
-import qualified Data.Text.Encoding
 import qualified Dhall.Map
 import qualified Dhall.Set
 import qualified Options.Applicative
@@ -335,11 +332,16 @@
         TList [ TInt 9, t₁, TString x ]
       where
         t₁ = encode t₀
-    encode (Project t₀ xs₀) =
+    encode (Project t₀ (Left xs₀)) =
         TList ([ TInt 10, t₁ ] ++ xs₁)
       where
         t₁  = encode t₀
         xs₁ = map TString (Dhall.Set.toList xs₀)
+    encode (Project t₀ (Right _T₀)) =
+        TList [ TInt 10, t₁, TList [ _T₁ ] ]
+      where
+        _T₁ = encode _T₀
+        t₁  = encode t₀
     encode (Union xTs₀) =
         TList [ TInt 11, TMap xTs₁ ]
       where
@@ -440,8 +442,7 @@
                     Nothing ->
                         TNull
                     Just h ->
-                        encode
-                            (Import { importHashed = h, importMode = Code })
+                        encode h
 
                 scheme₁ = case scheme₀ of
                     HTTP  -> 0
@@ -482,8 +483,7 @@
                 Nothing ->
                     TNull
                 Just digest ->
-                    TList
-                        [ TString "sha256", TString (Data.Text.pack (show digest)) ]
+                    TBytes ("\x12\x20" <> Data.ByteArray.convert digest)
 
             m = TInt (case importMode of Code -> 0; RawText -> 1)
 
@@ -660,12 +660,26 @@
     decode (TList (TInt 10 : t₁ : xs₁)) = do
         t₀ <- decode t₁
 
-        let process (TString x) = return x
-            process  _          = empty
+        let expectString (TString x) = return x
+            expectString  _          = empty
 
-        xs₀ <- traverse process xs₁
+        let decodeLeft = do
+                strings <- traverse expectString xs₁
 
-        return (Project t₀ (Dhall.Set.fromList xs₀))
+                return (Left (Dhall.Set.fromList strings))
+
+        let decodeRight =
+                case xs₁ of
+                    [ TList [ _T₁ ] ] -> do
+                        _T₀ <- decode _T₁
+
+                        return (Right _T₀)
+                    _ -> do
+                        empty
+
+        xs₀ <- decodeLeft <|> decodeRight
+
+        return (Project t₀ xs₀)
     decode (TList [ TInt 11, TMap xTs₁ ]) = do
         let process (TString x, _T₁) = do
                 mT₀ <- case _T₁ of
@@ -768,13 +782,17 @@
             TNull -> do
                 return Nothing
 
-            TList [ TString "sha256", TString base16Text ] -> do
-                let base16Bytes = Data.Text.Encoding.encodeUtf8 base16Text
-                digestBytes <- case Data.ByteArray.Encoding.convertFromBase Base16 base16Bytes of
-                    Left  _           -> empty
-                    Right digestBytes -> return (digestBytes :: Data.ByteString.ByteString)
+            TBytes bytes -> do
+                let (prefix, suffix) = Data.ByteString.splitAt 2 bytes
 
-                digest <- Crypto.Hash.digestFromByteString digestBytes
+                case prefix of
+                    "\x12\x20" -> return ()
+                    _          -> empty
+
+                digest <- case Crypto.Hash.digestFromByteString suffix of
+                    Nothing     -> empty
+                    Just digest -> return digest
+
                 return (Just digest)
 
             _ -> do
@@ -801,9 +819,11 @@
                 (headers, authority, paths, file, query) <- case xs of
                     headers₀ : TString authority : ys -> do
                         headers₁ <- case headers₀ of
-                            TNull -> return Nothing
+                            TNull -> do
+                                return Nothing
                             _     -> do
-                                Embed (Import { importHashed = headers }) <- decode headers₀
+                                headers <- decode headers₀
+
                                 return (Just headers)
                         (paths, file, query) <- process ys
                         return (headers₁, authority, paths, file, query)
@@ -856,6 +876,50 @@
 
     decode _ = empty
 
+strip55799Tag :: Term -> Term
+strip55799Tag term =
+    case term of
+        TInt a ->
+            TInt a
+        TInteger a ->
+            TInteger a
+        TBytes a ->
+            TBytes a
+        TBytesI a ->
+            TBytesI a
+        TString a ->
+            TString a
+        TStringI a ->
+            TStringI a
+        TList as ->
+            TList (fmap strip55799Tag as)
+        TListI as ->
+            TListI (fmap strip55799Tag as)
+        TMap as ->
+            TMap (fmap adapt as)
+          where
+            adapt (a, b) = (strip55799Tag a, strip55799Tag b)
+        TMapI as ->
+            TMapI (fmap adapt as)
+          where
+            adapt (a, b) = (strip55799Tag a, strip55799Tag b)
+        TTagged 55799 b ->
+            strip55799Tag b
+        TTagged a b->
+            TTagged a (strip55799Tag b)
+        TBool a ->
+            TBool a
+        TNull ->
+            TNull
+        TSimple a ->
+            TSimple a
+        THalf a ->
+            THalf a
+        TFloat a ->
+            TFloat a
+        TDouble a ->
+            TDouble a
+
 -- | Encode a Dhall expression as a CBOR `Term`
 encodeExpression :: Expr s Import -> Term
 encodeExpression = encode
@@ -867,13 +931,14 @@
         Just expression -> Right expression
         Nothing         -> Left (CBORIsNotDhall term)
   where
+    strippedTerm = strip55799Tag term
     -- This is the behavior specified by the standard
-    decodeWithoutVersion = decode term
+    decodeWithoutVersion = decode strippedTerm
 
     -- For backwards compatibility with older expressions that have a version
     -- tag to ease the migration
     decodeWithVersion = do
-        TList [ TString _, taggedTerm ] <- return term
+        TList [ TString _, taggedTerm ] <- return strippedTerm
         decode taggedTerm
 
 data DecodingFailure = CBORIsNotDhall Term
diff --git a/src/Dhall/Core.hs b/src/Dhall/Core.hs
--- a/src/Dhall/Core.hs
+++ b/src/Dhall/Core.hs
@@ -51,11 +51,14 @@
     -- * Pretty-printing
     , pretty
 
+    -- * Optics
+    , subExpressions
+    , chunkExprs
+
     -- * Miscellaneous
     , internalError
     , reservedIdentifiers
     , escapeText
-    , subExpressions
     , pathCharacter
     , throws
     ) where
@@ -82,6 +85,7 @@
 import Data.Traversable
 import Dhall.Map (Map)
 import Dhall.Set (Set)
+import Dhall.Src (Src)
 import {-# SOURCE #-} Dhall.Pretty.Internal
 import GHC.Generics (Generic)
 import Numeric.Natural (Natural)
@@ -121,7 +125,8 @@
     Note that Dhall does not support functions from terms to types and therefore
     Dhall is not a dependently typed language
 -}
-data Const = Type | Kind | Sort deriving (Show, Eq, Data, Bounded, Enum, Generic)
+data Const = Type | Kind | Sort
+    deriving (Show, Eq, Ord, Data, Bounded, Enum, Generic)
 
 instance Pretty Const where
     pretty = Pretty.unAnnotate . prettyConst
@@ -184,7 +189,7 @@
     , authority :: Text
     , path      :: File
     , query     :: Maybe Text
-    , headers   :: Maybe ImportHashed
+    , headers   :: Maybe (Expr Src Import)
     } deriving (Eq, Generic, Ord, Show)
 
 instance Pretty URL where
@@ -243,9 +248,9 @@
     import₀ <> Remote (URL { headers = headers₀, .. }) =
         Remote (URL { headers = headers₁, .. })
       where
-        importHashed₀ = ImportHashed Nothing import₀
+        importHashed₀ = Import (ImportHashed Nothing import₀) Code
 
-        headers₁ = fmap (importHashed₀ <>) headers₀
+        headers₁ = fmap (fmap (importHashed₀ <>)) headers₀
 
     _ <> import₁ =
         import₁
@@ -330,7 +335,7 @@
     appear as a numeric suffix.
 -}
 data Var = V Text !Integer
-    deriving (Data, Generic, Eq, Show)
+    deriving (Data, Generic, Eq, Ord, Show)
 
 instance IsString Var where
     fromString str = V (fromString str) 0
@@ -468,15 +473,16 @@
     | Merge (Expr s a) (Expr s a) (Maybe (Expr s a))
     -- | > Field e x                                ~  e.x
     | Field (Expr s a) Text
-    -- | > Project e xs                             ~  e.{ xs }
-    | Project (Expr s a) (Set Text)
+    -- | > Project e (Left xs)                      ~  e.{ xs }
+    -- | > Project e (Right t)                      ~  e.(t)
+    | Project (Expr s a) (Either (Set Text) (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, Foldable, Generic, Traversable, Show, Data)
+    deriving (Eq, Ord, Foldable, Generic, Traversable, Show, Data)
 
 -- This instance is hand-written due to the fact that deriving
 -- it does not give us an INLINABLE pragma. We annotate this fmap
@@ -544,7 +550,7 @@
   fmap f (Prefer e1 e2) = Prefer (fmap f e1) (fmap f e2)
   fmap f (Merge e1 e2 maybeE) = Merge (fmap f e1) (fmap f e2) (fmap (fmap f) maybeE)
   fmap f (Field e1 v) = Field (fmap f e1) v
-  fmap f (Project e1 vs) = Project (fmap f e1) vs
+  fmap f (Project e1 vs) = Project (fmap f e1) (fmap (fmap f) vs)
   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)
@@ -621,7 +627,7 @@
     Prefer a b           >>= k = Prefer (a >>= k) (b >>= k)
     Merge a b c          >>= k = Merge (a >>= k) (b >>= k) (fmap (>>= k) c)
     Field a b            >>= k = Field (a >>= k) b
-    Project a b          >>= k = Project (a >>= k) b
+    Project a b          >>= k = Project (a >>= k) (fmap (>>= k) b)
     Note a b             >>= k = Note a (b >>= k)
     ImportAlt a b        >>= k = ImportAlt (a >>= k) (b >>= k)
     Embed a              >>= k = k a
@@ -688,7 +694,7 @@
     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 (Field a b           ) = Field (first k a) b
-    first k (Project a b         ) = Project (first k a) 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)
     first _ (Embed a             ) = Embed a
@@ -702,7 +708,7 @@
     { variable   :: Text
     , annotation :: Maybe (Expr s a)
     , value      :: Expr s a
-    } deriving (Functor, Foldable, Generic, Traversable, Show, Eq, Data)
+    } deriving (Functor, Foldable, Generic, Traversable, Show, Eq, Ord, Data)
 
 instance Bifunctor Binding where
     first k (Binding a b c) = Binding a (fmap (first k) b) (first k c)
@@ -711,7 +717,7 @@
 
 -- | The body of an interpolated @Text@ literal
 data Chunks s a = Chunks [(Text, Expr s a)] Text
-    deriving (Functor, Foldable, Generic, Traversable, Show, Eq, Data)
+    deriving (Functor, Foldable, Generic, Traversable, Show, Eq, Ord, Data)
 
 instance Data.Semigroup.Semigroup (Chunks s a) where
     Chunks xysL zL <> Chunks         []    zR =
@@ -1274,7 +1280,7 @@
 denote (Prefer a b          ) = Prefer (denote a) (denote b)
 denote (Merge a b c         ) = Merge (denote a) (denote b) (fmap denote c)
 denote (Field a b           ) = Field (denote a) b
-denote (Project a b         ) = Project (denote a) b
+denote (Project a b         ) = Project (denote a) (fmap denote b)
 denote (ImportAlt a b       ) = ImportAlt (denote a) (denote b)
 denote (Embed a             ) = Embed a
 
@@ -1663,7 +1669,7 @@
                     Just v  -> loop v
                     Nothing -> Field <$> (RecordLit <$> traverse loop kvs) <*> pure x
             _ -> pure (Field r' x)
-    Project r xs     -> do
+    Project r (Left xs)-> do
         r' <- loop r
         case r' of
             RecordLit kvs ->
@@ -1673,13 +1679,22 @@
                       where
                         kvs' = Dhall.Map.fromList s
                     Nothing ->
-                        Project <$> (RecordLit <$> traverse loop kvs) <*> pure xs
+                        Project <$> (RecordLit <$> traverse loop kvs) <*> pure (Left xs)
               where
                 adapt x = do
                     v <- Dhall.Map.lookup x kvs
                     return (x, v)
             _   | null xs -> pure (RecordLit mempty)
-                | otherwise -> pure (Project r' xs)
+                | otherwise -> pure (Project r' (Left xs))
+    Project r (Right e1) -> do
+        e2 <- loop e1
+
+        case e2 of
+            Record kts -> do
+                loop (Project r (Left (Dhall.Set.fromList (Dhall.Map.keys kts))))
+            _ -> do
+                r' <- loop r
+                pure (Project r' (Right e2))
     Note _ e' -> loop e'
     ImportAlt l _r -> loop l
     Embed a -> pure (Embed a)
@@ -1905,9 +1920,14 @@
       Project r xs -> loop r &&
           case r of
               RecordLit kvs ->
-                  if all (flip Dhall.Map.member kvs) xs
-                      then False
-                      else True
+                  case xs of
+                      Left  s -> not (all (flip Dhall.Map.member kvs) s)
+                      Right e' ->
+                          case e' of
+                              Record kts ->
+                                  loop (Project r (Left (Dhall.Set.fromList (Dhall.Map.keys kts))))
+                              _ ->
+                                  False
               _ -> not (null xs)
       Note _ e' -> loop e'
       ImportAlt l _r -> loop l
@@ -2044,8 +2064,8 @@
 subExpressions _ (DoubleLit n) = pure (DoubleLit n)
 subExpressions _ DoubleShow = pure DoubleShow
 subExpressions _ Text = pure Text
-subExpressions f (TextLit (Chunks a b)) =
-    TextLit <$> (Chunks <$> traverse (traverse f) a <*> pure b)
+subExpressions f (TextLit chunks) =
+    TextLit <$> chunkExprs f chunks
 subExpressions f (TextAppend a b) = TextAppend <$> f a <*> f b
 subExpressions _ TextShow = pure TextShow
 subExpressions _ List = pure List
@@ -2078,6 +2098,14 @@
 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)
+
+-- | A traversal over the immediate sub-expressions in 'Chunks'.
+chunkExprs
+  :: Applicative f
+  => (Expr s a -> f (Expr t b))
+  -> Chunks s a -> f (Chunks t b)
+chunkExprs f (Chunks chunks final) =
+  flip Chunks final <$> traverse (traverse f) chunks
 
 {-| Returns `True` if the given `Char` is valid within an unquoted path
     component
diff --git a/src/Dhall/Diff.hs b/src/Dhall/Diff.hs
--- a/src/Dhall/Diff.hs
+++ b/src/Dhall/Diff.hs
@@ -256,9 +256,7 @@
     -> Map Text (Expr s a)
     -> Map Text (Expr s a)
     -> [Diff]
-diffKeyVals assign = diffKeysWith assign diffVals
-  where
-    diffVals l r = assign <> " " <> diffExpression l r
+diffKeyVals assign = diffKeysWith assign diffExpression
 
 diffKeysWith
     :: Diff
@@ -1022,8 +1020,10 @@
   where
     docs (Field aL bL) (Field aR bR) =
         Data.List.NonEmpty.cons (diffLabel bL bR) (docs aL aR)
-    docs (Project aL bL) (Project aR bR) =
+    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)
     docs aL aR =
         pure (diffPrimitiveExpression aL aR)
 diffSelectorExpression l@(Field {}) r =
@@ -1035,8 +1035,10 @@
   where
     docs (Field aL bL) (Field aR bR) =
         Data.List.NonEmpty.cons (diffLabel bL bR) (docs aL aR)
-    docs (Project aL bL) (Project aR bR) =
+    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)
     docs aL aR =
         pure (diffPrimitiveExpression aL aR)
 diffSelectorExpression l@(Project {}) r =
diff --git a/src/Dhall/Eval.hs b/src/Dhall/Eval.hs
--- a/src/Dhall/Eval.hs
+++ b/src/Dhall/Eval.hs
@@ -87,6 +87,7 @@
 import qualified Data.Text
 import qualified Dhall.Binary
 import qualified Dhall.Map
+import qualified Dhall.Set
 import qualified Text.Printf
 
 ----------------------------------------------------------------------------------------------------
@@ -214,7 +215,7 @@
   | VMerge !(Val a) !(Val a) !(Maybe (Val a))
   | VField !(Val a) !Text
   | VInject !(Map Text (Maybe (Val a))) !Text !(Maybe (Val a))
-  | VProject !(Val a) !(Set Text)
+  | VProject !(Val a) !(Either (Set Text) (Val a))
   | VEmbed a
 
 vFun :: Val a -> Val a -> Val a
@@ -367,7 +368,7 @@
                             VHLam (Typed "zero" natural) $ \zero ->
                               let go !acc 0 = acc
                                   go  acc n = go (vApp succ acc) (n - 1)
-                              in go zero n
+                              in go zero (fromIntegral n :: Integer)
                           n ->
                             VHLam (NaturalFoldCl n) $ \natural -> VPrim $ \succ -> VPrim $ \zero ->
                               VNaturalFold n natural succ zero
@@ -536,14 +537,20 @@
                             Just Nothing  -> VInject m k Nothing
                             _             -> error errorMsg
                           t -> VField t k
-    Project t ks     -> if null ks then
+    Project t (Left ks) ->
+                        if null ks then
                           VRecordLit mempty
                         else case evalE t of
                           VRecordLit kvs
                             | Just s <- traverse (\k -> (k,) <$> Dhall.Map.lookup k kvs) (toList ks)
                               -> VRecordLit (Dhall.Map.sort (Dhall.Map.fromList s))
                             | otherwise -> error errorMsg
-                          t -> VProject t ks
+                          t -> VProject t (Left ks)
+    Project t (Right e) ->
+                        case evalE e of
+                          VRecord kts ->
+                            evalE (Project t (Left (Dhall.Set.fromList (Dhall.Map.keys kts))))
+                          e' -> VProject (evalE t) (Right e')
     Note _ e         -> evalE e
     ImportAlt t _    -> evalE t
     Embed a          -> VEmbed a
@@ -559,6 +566,12 @@
   go _  _  = False
 {-# inline eqListBy #-}
 
+eqMapsBy :: Ord k => (v -> v -> Bool) -> Map k v -> Map k v -> Bool
+eqMapsBy f mL mR = eqListBy eq (Dhall.Map.toList mL) (Dhall.Map.toList mR)
+  where
+    eq (kL, vL) (kR, vR) = kL == kR && f vL vR
+{-# inline eqMapsBy #-}
+
 eqMaybeBy :: (a -> a -> Bool) -> Maybe a -> Maybe a -> Bool
 eqMaybeBy f = go where
   go (Just x) (Just y) = f x y
@@ -670,18 +683,19 @@
     (VSome t                 , VSome t'                    ) -> convE t t'
     (VNone _                 , VNone _                     ) -> True
     (VOptionalBuild _ t      , VOptionalBuild _ t'         ) -> convE t t'
-    (VRecord m               , VRecord m'                  ) -> eqListBy convE (toList m) (toList m')
-    (VRecordLit m            , VRecordLit m'               ) -> eqListBy convE (toList m) (toList m')
-    (VUnion m                , VUnion m'                   ) -> eqListBy (eqMaybeBy convE) (toList m) (toList m')
+    (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' &&
-                                                                  eqListBy (eqMaybeBy convE) (toList m) (toList m')
+                                                                  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'
     (VMerge t u _            , VMerge t' u' _              ) -> convE t t' && convE u u'
     (VField t k              , VField t' k'                ) -> convE t t' && k == k'
-    (VProject t ks           , VProject t' ks'             ) -> convE t t' && ks == ks'
-    (VInject m k mt          , VInject m' k' mt'           ) -> eqListBy (eqMaybeBy convE) (toList m) (toList m')
+    (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'
+    (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'
     (VOptionalFold a t _ u v , VOptionalFold a' t' _ u' v' ) ->
@@ -813,7 +827,7 @@
     VPrefer t u                   -> Prefer (quoteE t) (quoteE u)
     VMerge t u ma                 -> Merge (quoteE t) (quoteE u) (quoteE <$> ma)
     VField t k                    -> Field (quoteE t) k
-    VProject t ks                 -> Project (quoteE t) ks
+    VProject t p                  -> Project (quoteE t) (fmap quoteE p)
     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
diff --git a/src/Dhall/Freeze.hs b/src/Dhall/Freeze.hs
--- a/src/Dhall/Freeze.hs
+++ b/src/Dhall/Freeze.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards   #-}
 
 -- | This module contains the implementation of the @dhall freeze@ subcommand
 
@@ -7,6 +8,10 @@
       freeze
     , freezeImport
     , freezeRemoteImport
+
+      -- * Types
+    , Scope(..)
+    , Intent(..)
     ) where
 
 import Control.Exception (SomeException)
@@ -29,6 +34,7 @@
 import qualified Data.Text.IO
 import qualified Dhall.Core
 import qualified Dhall.Import
+import qualified Dhall.Optics
 import qualified Dhall.TypeCheck
 import qualified System.FilePath
 import qualified System.IO
@@ -94,12 +100,6 @@
         Remote {} -> freezeImport directory _standardVersion import_
         _         -> return import_
 
-parseExpr :: String -> Text -> IO (Text, Expr Src Import)
-parseExpr src txt =
-    case exprAndHeaderFromText src txt of
-        Left err -> Control.Exception.throwIO err
-        Right x  -> return x
-
 writeExpr :: Maybe FilePath -> (Text, Expr s Import) -> CharacterSet -> IO ()
 writeExpr inplace (header, expr) characterSet = do
     let doc =  Pretty.pretty header
@@ -121,17 +121,35 @@
                else
                  Pretty.renderIO System.IO.stdout unAnnotated
 
+-- | Specifies which imports to freeze
+data Scope
+    = OnlyRemoteImports
+    -- ^ Freeze only remote imports (i.e. URLs)
+    | AllImports
+    -- ^ Freeze all imports (including paths and environment variables)
+
+-- | Specifies why we are adding semantic integrity checks
+data Intent
+    = Secure
+    -- ^ Protect imports with an integrity check without a fallback so that
+    --   import resolution fails if the import changes
+    | Cache
+    -- ^ Protect imports with an integrity check and also add a fallback import
+    --   import without an integrity check.  This is useful if you only want to
+    --   cache imports when possible but still gracefully degrade to resolving
+    --   them if the semantic integrity check has changed.
+
 -- | Implementation of the @dhall freeze@ subcommand
 freeze
     :: Maybe FilePath
     -- ^ Modify file in-place if present, otherwise read from @stdin@ and write
     --   to @stdout@
-    -> Bool
-    -- ^ If `True` then freeze all imports, otherwise freeze only remote imports
+    -> Scope
+    -> Intent
     -> CharacterSet
     -> StandardVersion
     -> IO ()
-freeze inplace everything characterSet _standardVersion = do
+freeze inplace scope intent characterSet _standardVersion = do
     (text, directory) <- case inplace of
         Nothing -> do
             text <- Data.Text.IO.getContents
@@ -143,11 +161,61 @@
 
             return (text, System.FilePath.takeDirectory file)
 
-    (header, parsedExpression) <- parseExpr srcInfo text
+    (header, parsedExpression) <- Dhall.Core.throws (exprAndHeaderFromText srcInfo text)
 
-    let freezeFunction = if everything then freezeImport else freezeRemoteImport
+    let freezeScope =
+            case scope of
+                AllImports        -> freezeImport
+                OnlyRemoteImports -> freezeRemoteImport
 
-    frozenExpression <- traverse (freezeFunction directory _standardVersion) parsedExpression
+    let freezeFunction = freezeScope directory _standardVersion
+
+    let cache
+            (ImportAlt
+                (Embed
+                    (Import { importHashed = ImportHashed { hash = Just _expectedHash } })
+                )
+                import_@(ImportAlt
+                    (Embed
+                        (Import { importHashed = ImportHashed { hash = Just _actualHash } })
+                    )
+                    _
+                )
+            ) = do
+                {- Here we could actually compare the `_expectedHash` and
+                   `_actualHash` to see if they differ, but we choose not to do
+                   so and instead automatically accept the `_actualHash`.  This
+                   is done for the same reason that the `freeze*` functions
+                   ignore hash mismatches: the user intention when using `dhall
+                   freeze` is to update the hash, which they expect to possibly
+                   change.
+                -}
+                return import_
+        cache
+            (Embed import_@(Import { importHashed = ImportHashed { hash = Nothing } })) = do
+                frozenImport <- freezeFunction import_
+
+                {- The two imports can be the same if the import is local and
+                   `freezeFunction` only freezes remote imports
+                -}
+                if frozenImport /= import_
+                    then return (ImportAlt (Embed frozenImport) (Embed import_))
+                    else return (Embed import_)
+        cache expression = do
+            return expression
+
+    let rewrite expression =
+            case intent of
+                Secure ->
+                    traverse freezeFunction expression
+                Cache  ->
+                    Dhall.Optics.transformMOf
+                        Dhall.Core.subExpressions
+                        cache
+                        (Dhall.Core.denote expression)
+
+    frozenExpression <- rewrite parsedExpression
+
     writeExpr inplace (header, frozenExpression) characterSet
         where
             srcInfo = fromMaybe "(stdin)" inplace
diff --git a/src/Dhall/Import.hs b/src/Dhall/Import.hs
--- a/src/Dhall/Import.hs
+++ b/src/Dhall/Import.hs
@@ -125,6 +125,7 @@
     , MissingFile(..)
     , MissingEnvironmentVariable(..)
     , MissingImports(..)
+    , HashMismatch(..)
     ) where
 
 import Control.Applicative (Alternative(..))
@@ -371,7 +372,7 @@
         Local prefix (canonicalize file)
 
     canonicalize (Remote (URL {..})) =
-        Remote (URL { path = canonicalize path, headers = fmap canonicalize headers, ..})
+        Remote (URL { path = canonicalize path, headers = fmap (fmap canonicalize) headers, ..})
 
     canonicalize (Env name) =
         Env name
@@ -457,7 +458,7 @@
     return (foldr cons prefixPath cs)
 
 -- | Parse an expression from a `Import` containing a Dhall program
-exprFromImport :: Import -> StateT (Status IO) IO (Expr Src Import)
+exprFromImport :: Import -> StateT (Status IO) IO Resolved
 exprFromImport here@(Import {..}) = do
     let ImportHashed {..} = importHashed
 
@@ -483,9 +484,13 @@
         Dhall.Core.throws (Dhall.Binary.decodeExpression term)
 
     case result of
-        Just expression -> return expression
-        Nothing         -> exprFromUncachedImport here
+        Just resolvedExpression -> do
+            let newImport = here
 
+            return (Resolved {..})
+        Nothing -> do
+            exprFromUncachedImport here
+
 {-| Save an expression to the specified `Import`
 
     Currently this only works for cached imports and ignores other types of
@@ -594,11 +599,11 @@
             Just homeDirectory -> return (homeDirectory </> ".cache")
             Nothing            -> empty
 
-exprFromUncachedImport :: Import -> StateT (Status IO) IO (Expr Src Import)
-exprFromUncachedImport (Import {..}) = do
+exprFromUncachedImport :: Import -> StateT (Status IO) IO Resolved
+exprFromUncachedImport import_@(Import {..}) = do
     let ImportHashed {..} = importHashed
 
-    (path, text) <- case importType of
+    (path, text, newImport) <- case importType of
         Local prefix file -> liftIO $ do
             path   <- localToPath prefix file
             exists <- Directory.doesFileExist path
@@ -609,13 +614,14 @@
 
             text <- Data.Text.IO.readFile path
 
-            return (path, text)
+            return (path, text, import_)
 
-        Remote url@URL { headers = maybeHeaders } -> do
-            mheaders <- case maybeHeaders of
-                Nothing            -> return Nothing
-                Just importHashed_ -> do
-                    expr <- loadWith (Embed (Import importHashed_ Code))
+        Remote url@URL { headers = maybeHeadersExpression } -> do
+            maybeHeadersAndExpression <- case maybeHeadersExpression of
+                Nothing -> do
+                    return Nothing
+                Just headersExpression -> do
+                    expr <- loadWith headersExpression
 
                     let expected :: Expr Src X
                         expected =
@@ -642,12 +648,28 @@
 
                     case toHeaders expr' of
                         Just headers -> do
-                            return (Just headers)
+                            return (Just (headers, expr'))
                         Nothing      -> do
                             liftIO (throwIO InternalError)
 
 #ifdef MIN_VERSION_http_client
-            fetchFromHttpUrl url mheaders
+            let maybeHeaders = fmap fst maybeHeadersAndExpression
+
+            let newHeaders =
+                    fmap (fmap absurd . snd) maybeHeadersAndExpression
+
+            (path, text) <- fetchFromHttpUrl url maybeHeaders
+
+            let newImport = Import
+                    { importHashed = ImportHashed
+                        { importType =
+                            Remote (url { headers = newHeaders })
+                        , ..
+                        }
+                    , ..
+                    }
+
+            return (path, text, newImport)
 #else
             let urlString = Text.unpack (Dhall.Core.pretty url)
 
@@ -657,8 +679,10 @@
         Env env -> liftIO $ do
             x <- System.Environment.lookupEnv (Text.unpack env)
             case x of
-                Just string -> return (Text.unpack env, Text.pack string)
-                Nothing     -> throwMissingImport (MissingEnvironmentVariable env)
+                Just string -> do
+                    return (Text.unpack env, Text.pack string, import_)
+                Nothing -> do
+                    throwMissingImport (MissingEnvironmentVariable env)
 
         Missing -> liftIO $ do
             throwM (MissingImports [])
@@ -674,12 +698,14 @@
             case Text.Megaparsec.parse parser path text of
                 Left errInfo -> do
                     liftIO (throwIO (ParseError errInfo text))
-                Right expr -> do
-                    return expr
+                Right resolvedExpression -> do
+                    return (Resolved {..})
 
         RawText -> do
-            return (TextLit (Chunks [] text))
+            let resolvedExpression = TextLit (Chunks [] text)
 
+            return (Resolved {..})
+
 -- | Default starting `Status`, importing relative to the given directory.
 emptyStatus :: FilePath -> Status IO
 emptyStatus = emptyStatusWith exprFromImport exprToImport
@@ -739,7 +765,7 @@
                     let handler₀
                             :: (MonadCatch m)
                             => MissingImports
-                            -> StateT (Status m) m (Expr Src Import)
+                            -> StateT (Status m) m Resolved
                         handler₀ (MissingImports es) =
                           throwM
                             (MissingImports
@@ -752,7 +778,7 @@
                         handler₁
                             :: (MonadCatch m)
                             => SomeException
-                            -> StateT (Status m) m (Expr Src Import)
+                            -> StateT (Status m) m Resolved
                         handler₁ e =
                           throwMissingImport (Imported _stack' e)
 
@@ -760,8 +786,10 @@
                     -- that might still contain imports)
                     let loadDynamic = _resolver child
 
-                    expr' <- loadDynamic `catches` [ Handler handler₀, Handler handler₁ ]
+                    Resolved {..} <- loadDynamic `catches` [ Handler handler₀, Handler handler₁ ]
 
+                    let stackWithNewImport = NonEmpty.cons newImport _stack
+
                     let childNodeId = userNodeId _nextNodeId
 
                     -- Increment the next node id
@@ -770,8 +798,8 @@
                     -- Make current node the dot graph
                     zoom dot . State.put $ importNode childNodeId child
 
-                    zoom stack (State.put _stack')
-                    expr'' <- loadWith expr'
+                    zoom stack (State.put stackWithNewImport)
+                    expr'' <- loadWith resolvedExpression
                     zoom stack (State.put _stack)
 
                     zoom dot . State.modify $ \getSubDot -> do
@@ -896,7 +924,7 @@
   Prefer a b           -> Prefer <$> loadWith a <*> loadWith b
   Merge a b c          -> Merge <$> loadWith a <*> loadWith b <*> mapM loadWith c
   Field a b            -> Field <$> loadWith a <*> pure b
-  Project a b          -> Project <$> loadWith a <*> pure b
+  Project a b          -> Project <$> loadWith a <*> mapM loadWith b
   Note a b             -> do
       let handler e = throwM (SourcedException a (e :: MissingImports))
 
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
@@ -28,7 +28,6 @@
 import qualified Control.Monad.Trans.State.Strict as State
 import qualified Data.Text                        as Text
 import qualified Data.Text.Encoding
-import qualified Dhall.Core
 import qualified Dhall.Util
 import qualified Network.URI.Encode               as URI.Encode
 
@@ -239,7 +238,7 @@
     -> StateT (Status m) IO (String, Text.Text)
 #ifdef __GHCJS__
 fetchFromHttpUrl childURL Nothing = do
-    let childURLText = Dhall.Core.pretty childURL
+    let childURLText = renderURL childURL
 
     let childURLString = Text.unpack childURLText
 
@@ -256,7 +255,7 @@
     fail "Dhall does not yet support custom headers when built using GHCJS"
 #else
 fetchFromHttpUrl childURL mheaders = do
-    let childURLString = Text.unpack (Dhall.Core.pretty childURL)
+    let childURLString = Text.unpack (renderURL childURL)
 
     m <- needManager
 
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
@@ -35,6 +35,14 @@
 import qualified Data.Map      as Map
 import qualified Data.Text
 
+data Resolved = Resolved
+    { resolvedExpression :: Expr Src Import
+    -- ^ Expression with its immediate imports resolved
+    , newImport          :: Import
+    -- ^ New import to use in place of the original import for chaining
+    --   downstream imports
+    }
+
 -- | State threaded throughout the import process
 data Status m = Status
     { _stack :: NonEmpty Import
@@ -60,14 +68,14 @@
 
     , _startingContext :: Context (Expr Src X)
 
-    , _resolver :: Import -> StateT (Status m) m (Expr Src Import)
+    , _resolver :: Import -> StateT (Status m) m Resolved
 
     , _cacher :: Import -> Expr Src X -> StateT (Status m) m ()
     }
 
 -- | Default starting `Status` that is polymorphic in the base `Monad`
 emptyStatusWith
-    :: (Import -> StateT (Status m) m (Expr Src Import))
+    :: (Import -> StateT (Status m) m Resolved)
     -> (Import -> Expr Src X -> StateT (Status m) m ())
     -> FilePath
     -> Status m
@@ -144,7 +152,7 @@
 
 resolver
     :: Functor f
-    => LensLike' f (Status m) (Import -> StateT (Status m) m (Expr Src Import))
+    => LensLike' f (Status m) (Import -> StateT (Status m) m Resolved)
 resolver k s = fmap (\x -> s { _resolver = x }) (k (_resolver s))
 
 cacher
diff --git a/src/Dhall/Lint.hs b/src/Dhall/Lint.hs
--- a/src/Dhall/Lint.hs
+++ b/src/Dhall/Lint.hs
@@ -12,9 +12,9 @@
 import Data.List.NonEmpty (NonEmpty(..))
 import Data.Semigroup ((<>))
 import Dhall.Core (Binding(..), Expr(..), Import, Var(..), subExpressions)
-import Lens.Family (ASetter, over)
 
 import qualified Dhall.Core
+import qualified Dhall.Optics
 
 {-| Automatically improve a Dhall expression
 
@@ -26,7 +26,7 @@
 -}
 lint :: Expr s Import -> Expr t Import
 lint =
-  rewriteOf
+  Dhall.Optics.rewriteOf
     subExpressions
     ( \e ->
                 removeLetInLet e
@@ -59,10 +59,3 @@
 optionalLitToSomeNone (OptionalLit _ (Just b)) = Just (Some b)
 optionalLitToSomeNone (OptionalLit a Nothing) = Just (App None a)
 optionalLitToSomeNone _ = Nothing
-
-
-rewriteOf :: ASetter a b a b -> (b -> Maybe a) -> a -> b
-rewriteOf l f = go where go = transformOf l (\x -> maybe x go (f x))
-
-transformOf :: ASetter a b a b -> (b -> b) -> a -> b
-transformOf l f = go where go = f . over l go
diff --git a/src/Dhall/Main.hs b/src/Dhall/Main.hs
--- a/src/Dhall/Main.hs
+++ b/src/Dhall/Main.hs
@@ -27,6 +27,7 @@
 import Data.Version (showVersion)
 import Dhall.Binary (StandardVersion)
 import Dhall.Core (Expr(..), Import)
+import Dhall.Freeze (Intent(..), Scope(..))
 import Dhall.Import (Imported(..))
 import Dhall.Parser (Src)
 import Dhall.Pretty (Ann, CharacterSet(..), annToAnsiStyle, layoutOpts)
@@ -83,19 +84,19 @@
 
 -- | The subcommands for the @dhall@ executable
 data Mode
-    = Default { annotate :: Bool, alpha :: Bool }
+    = Default { file :: Maybe FilePath, annotate :: Bool, alpha :: Bool }
     | Version
-    | Resolve { resolveMode :: Maybe ResolveMode }
-    | Type
-    | Normalize { alpha :: Bool }
+    | Resolve { file :: Maybe FilePath, resolveMode :: Maybe ResolveMode }
+    | Type { file :: Maybe FilePath }
+    | Normalize { file :: Maybe FilePath, alpha :: Bool }
     | Repl
     | Format { formatMode :: Dhall.Format.FormatMode }
-    | Freeze { inplace :: Maybe FilePath, all_ :: Bool }
+    | Freeze { inplace :: Maybe FilePath, all_ :: Bool, cache :: Bool }
     | Hash
     | Diff { expr1 :: Text, expr2 :: Text }
     | Lint { inplace :: Maybe FilePath }
-    | Encode { json :: Bool }
-    | Decode { json :: Bool }
+    | Encode { file :: Maybe FilePath, json :: Bool }
+    | Decode { file :: Maybe FilePath, json :: Bool }
 
 data ResolveMode
     = Dot
@@ -141,15 +142,15 @@
     <|> subcommand
             "resolve"
             "Resolve an expression's imports"
-            (Resolve <$> parseResolveMode)
+            (Resolve <$> optional parseFile <*> parseResolveMode)
     <|> subcommand
             "type"
             "Infer an expression's type"
-            (pure Type)
+            (Type <$> optional parseFile)
     <|> subcommand
             "normalize"
             "Normalize an expression"
-            (Normalize <$> parseAlpha)
+            (Normalize <$> optional parseFile <*> parseAlpha)
     <|> subcommand
             "repl"
             "Interpret expressions in a REPL"
@@ -173,22 +174,29 @@
     <|> subcommand
             "freeze"
             "Add integrity checks to remote import statements of an expression"
-            (Freeze <$> optional parseInplace <*> parseAllFlag)
+            (Freeze <$> optional parseInplace <*> parseAllFlag <*> parseCacheFlag)
     <|> subcommand
             "encode"
             "Encode a Dhall expression to binary"
-            (Encode <$> parseJSONFlag)
+            (Encode <$> optional parseFile <*> parseJSONFlag)
     <|> subcommand
             "decode"
             "Decode a Dhall expression from binary"
-            (Decode <$> parseJSONFlag)
-    <|> (Default <$> parseAnnotate <*> parseAlpha)
+            (Decode <$> optional parseFile <*> parseJSONFlag)
+    <|> (Default <$> optional parseFile <*> parseAnnotate <*> parseAlpha)
   where
     argument =
             fmap Data.Text.pack
         .   Options.Applicative.strArgument
         .   Options.Applicative.metavar
 
+    parseFile =
+        Options.Applicative.strOption
+            (   Options.Applicative.long "file"
+            <>  Options.Applicative.help "Read expression from a file instead of standard input"
+            <>  Options.Applicative.metavar "FILE"
+            )
+
     parseAlpha =
         Options.Applicative.switch
             (   Options.Applicative.long "alpha"
@@ -240,6 +248,12 @@
         <>  Options.Applicative.help "Add integrity checks to all imports (not just remote imports)"
         )
 
+    parseCacheFlag =
+        Options.Applicative.switch
+        (   Options.Applicative.long "cache"
+        <>  Options.Applicative.help "Add fallback unprotected imports when using integrity checks purely for caching purposes"
+        )
+
     parseCheck =
         Options.Applicative.switch
         (   Options.Applicative.long "check"
@@ -251,9 +265,13 @@
         adapt True  path    = Dhall.Format.Check {..}
         adapt False inplace = Dhall.Format.Modify {..}
 
-getExpression :: IO (Expr Src Import)
-getExpression = do
-    inText <- Data.Text.IO.getContents
+getExpression :: Maybe FilePath -> IO (Expr Src Import)
+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
 
     Dhall.Core.throws (Dhall.Parser.exprFromText "(stdin)" inText)
 
@@ -275,9 +293,14 @@
 
     GHC.IO.Encoding.setLocaleEncoding System.IO.utf8
 
-    let status =
-            set Dhall.Import.standardVersion standardVersion (Dhall.Import.emptyStatus ".")
-
+    let toStatus maybeFile =
+            set Dhall.Import.standardVersion standardVersion
+                (Dhall.Import.emptyStatus file)
+          where
+            file = case maybeFile of
+                Just "-" -> "."
+                Just f   -> f
+                Nothing  -> "."
 
     let handle =
                 Control.Exception.handle handler2
@@ -342,9 +365,9 @@
             Data.Text.IO.putStrLn line₁
 
         Default {..} -> do
-            expression <- getExpression
+            expression <- getExpression file
 
-            resolvedExpression <- State.evalStateT (Dhall.Import.loadWith expression) status
+            resolvedExpression <- State.evalStateT (Dhall.Import.loadWith expression) (toStatus file)
 
             inferredType <- Dhall.Core.throws (Dhall.TypeCheck.typeOf resolvedExpression)
 
@@ -362,28 +385,28 @@
 
             render System.IO.stdout annotatedExpression
 
-        Resolve (Just Dot) -> do
-            expression <- getExpression
+        Resolve { resolveMode = Just Dot, ..} -> do
+            expression <- getExpression file
 
             (Dhall.Import.Types.Status { _dot}) <-
-                State.execStateT (Dhall.Import.loadWith expression) status
+                State.execStateT (Dhall.Import.loadWith expression) (toStatus file)
 
             putStr . ("strict " <>) . Text.Dot.showDot $
                    Text.Dot.attribute ("rankdir", "LR") >>
                    _dot
 
-        Resolve (Just ListImmediateDependencies) -> do
-            expression <- getExpression
+        Resolve { resolveMode = Just ListImmediateDependencies, ..} -> do
+            expression <- getExpression file
 
             mapM_ (print
                         . Pretty.pretty
                         . Dhall.Core.importHashed) expression
 
-        Resolve (Just ListTransitiveDependencies) -> do
-            expression <- getExpression
+        Resolve { resolveMode = Just ListTransitiveDependencies, ..} -> do
+            expression <- getExpression file
 
             (Dhall.Import.Types.Status { _cache }) <-
-                State.execStateT (Dhall.Import.loadWith expression) status
+                State.execStateT (Dhall.Import.loadWith expression) (toStatus file)
 
             mapM_ print
                  .   fmap (   Pretty.pretty
@@ -392,15 +415,15 @@
                  .   Data.Map.keys
                  $   _cache
 
-        Resolve (Nothing) -> do
-            expression <- getExpression
+        Resolve { resolveMode = Nothing, ..} -> do
+            expression <- getExpression file
 
             (resolvedExpression, _) <-
-                State.runStateT (Dhall.Import.loadWith expression) status
+                State.runStateT (Dhall.Import.loadWith expression) (toStatus file)
             render System.IO.stdout resolvedExpression
 
         Normalize {..} -> do
-            expression <- getExpression
+            expression <- getExpression file
 
             resolvedExpression <- Dhall.Import.assertNoImports expression
 
@@ -415,8 +438,8 @@
 
             render System.IO.stdout alphaNormalizedExpression
 
-        Type -> do
-            expression <- getExpression
+        Type {..} -> do
+            expression <- getExpression file
 
             resolvedExpression <- Dhall.Import.assertNoImports expression
 
@@ -440,8 +463,12 @@
             Dhall.Format.format (Dhall.Format.Format {..})
 
         Freeze {..} -> do
-            Dhall.Freeze.freeze inplace all_ characterSet standardVersion
+            let scope = if all_ then AllImports else OnlyRemoteImports
 
+            let intent = if cache then Cache else Secure
+
+            Dhall.Freeze.freeze inplace scope intent characterSet standardVersion
+
         Hash -> do
             Dhall.Hash.hash standardVersion
 
@@ -473,7 +500,7 @@
                     renderDoc System.IO.stdout doc
 
         Encode {..} -> do
-            expression <- getExpression
+            expression <- getExpression file
 
             let term = Dhall.Binary.encode expression
 
@@ -493,7 +520,10 @@
                     Data.ByteString.Lazy.putStr bytes
 
         Decode {..} -> do
-            bytes <- Data.ByteString.Lazy.getContents
+            bytes <- do
+                case file of
+                    Just f  -> Data.ByteString.Lazy.readFile f
+                    Nothing -> Data.ByteString.Lazy.getContents
 
             term <- do
                 if json
diff --git a/src/Dhall/Map.hs b/src/Dhall/Map.hs
--- a/src/Dhall/Map.hs
+++ b/src/Dhall/Map.hs
@@ -75,8 +75,11 @@
     deriving (Data)
 
 instance (Eq k, Eq v) => Eq (Map k v) where
-  (Map m1 ks) == (Map m2 ks') = m1 == m2 && ks == ks'
+  Map m1 ks == Map m2 ks' = m1 == m2 && ks == ks'
   {-# INLINABLE (==) #-}
+
+instance (Ord k, Ord v) => Ord (Map k v) where
+  compare (Map mL ksL) (Map mR ksR) = compare mL mR <> compare ksL ksR
 
 instance Functor (Map k) where
   fmap f (Map m ks) = Map (fmap f m) ks
diff --git a/src/Dhall/Optics.hs b/src/Dhall/Optics.hs
new file mode 100644
--- /dev/null
+++ b/src/Dhall/Optics.hs
@@ -0,0 +1,53 @@
+{-| This module contains some useful utilities copy-and-pasted from the @lens@
+    library to avoid a dependency which are used internally and also re-exported
+    for convenience
+-}
+
+module Dhall.Optics
+    ( -- * Utilities
+      rewriteOf
+    , transformOf
+    , rewriteMOf
+    , transformMOf
+    , mapMOf
+    ) where
+
+import Control.Applicative (WrappedMonad(..))
+import Data.Profunctor.Unsafe ((#.))
+import Lens.Family (ASetter, LensLike, over)
+
+-- | Identical to @"Control.Lens".`Control.Lens.rewriteOf`@
+rewriteOf :: ASetter a b a b -> (b -> Maybe a) -> a -> b
+rewriteOf l f = go
+  where
+    go = transformOf l (\x -> maybe x go (f x))
+{-# INLINE rewriteOf #-}
+
+-- | Identical to @"Control.Lens".`Control.Lens.transformOf`@
+transformOf :: ASetter a b a b -> (b -> b) -> a -> b
+transformOf l f = go
+  where
+    go = f . over l go
+{-# INLINE transformOf #-}
+
+-- | Identical to @"Control.Lens".`Control.Lens.rewriteMOf`@
+rewriteMOf
+    :: Monad m
+    => LensLike (WrappedMonad m) a b a b -> (b -> m (Maybe a)) -> a -> m b
+rewriteMOf l f = go
+  where
+    go = transformMOf l (\x -> f x >>= maybe (return x) go)
+{-# INLINE rewriteMOf #-}
+
+-- | Identical to @"Control.Lens".`Control.Lens.transformMOf`@
+transformMOf
+    :: Monad m => LensLike (WrappedMonad m) a b a b -> (b -> m b) -> a -> m b
+transformMOf l f = go
+  where
+    go t = mapMOf l go t >>= f
+{-# INLINE transformMOf #-}
+
+-- | Identical to @"Control.Lens".`Control.Lens.mapMOf`@
+mapMOf :: LensLike (WrappedMonad m) s t a b -> (a -> m b) -> s -> m t
+mapMOf l cmd = unwrapMonad #. l (WrapMonad #. cmd)
+{-# INLINE mapMOf #-}
diff --git a/src/Dhall/Parser.hs b/src/Dhall/Parser.hs
--- a/src/Dhall/Parser.hs
+++ b/src/Dhall/Parser.hs
@@ -23,6 +23,7 @@
 import Data.Text (Text)
 import Data.Void (Void)
 import Dhall.Core
+import Dhall.Src (Src(..))
 import Prelude hiding (const, pi)
 
 import qualified Data.Text
diff --git a/src/Dhall/Parser/Combinators.hs b/src/Dhall/Parser/Combinators.hs
--- a/src/Dhall/Parser/Combinators.hs
+++ b/src/Dhall/Parser/Combinators.hs
@@ -1,15 +1,13 @@
-{-# LANGUAGE CPP                        #-}
-{-# LANGUAGE DeriveAnyClass             #-}
-{-# LANGUAGE DeriveDataTypeable         #-}
-{-# LANGUAGE MultiParamTypeClasses      #-}
-{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE CPP                   #-}
+{-# LANGUAGE DeriveAnyClass        #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings     #-}
 module Dhall.Parser.Combinators where
 
 
 import           Control.Applicative        (Alternative (..), liftA2)
 import           Control.Exception          (Exception)
 import           Control.Monad              (MonadPlus (..))
-import           Data.Data                  (Data)
 import           Data.Semigroup             (Semigroup (..))
 import           Data.Sequence              (ViewL (..))
 import           Data.String                (IsString (..))
@@ -18,6 +16,7 @@
 import           Data.Void                  (Void)
 import           Dhall.Map                  (Map)
 import           Dhall.Set                  (Set)
+import           Dhall.Src                  (Src(..))
 import           Prelude                    hiding (const, pi)
 import           Text.Parser.Combinators    (try, (<?>))
 import           Text.Parser.Token          (TokenParsing (..))
@@ -31,7 +30,6 @@
 import qualified Data.Text.Prettyprint.Doc.Render.String as Pretty
 import qualified Dhall.Map
 import qualified Dhall.Pretty
-import qualified Dhall.Util
 import qualified Dhall.Set
 import qualified Text.Megaparsec
 #if !MIN_VERSION_megaparsec(7, 0, 0)
@@ -41,13 +39,7 @@
 import qualified Text.Parser.Char
 import qualified Text.Parser.Combinators
 import qualified Text.Parser.Token.Style
-import qualified Text.Printf
 
--- | Source code extract
-data Src = Src !Text.Megaparsec.SourcePos !Text.Megaparsec.SourcePos Text
-  -- Text field is intentionally lazy
-  deriving (Data, Eq, Show)
-
 data SourcedException e = SourcedException Src e
 
 instance Exception e => Exception (SourcedException e)
@@ -70,38 +62,6 @@
         a == a' && b == b'
 {-# INLINE laxSrcEq #-}
 
-instance Pretty Src where
-    pretty (Src begin _ text) =
-            pretty (Dhall.Util.snip numberedLines)
-        <>  "\n"
-        <>  pretty (Text.Megaparsec.sourcePosPretty begin)
-      where
-        prefix = Data.Text.replicate (n - 1) " "
-          where
-            n = Text.Megaparsec.unPos (Text.Megaparsec.sourceColumn begin)
-
-        ls = Data.Text.lines (prefix <> text)
-
-        numberOfLines = length ls
-
-        minimumNumber =
-            Text.Megaparsec.unPos (Text.Megaparsec.sourceLine begin)
-
-        maximumNumber = minimumNumber + numberOfLines - 1
-
-        numberWidth :: Int
-        numberWidth =
-            truncate (logBase (10 :: Double) (fromIntegral maximumNumber)) + 1
-
-        adapt n line = Data.Text.pack outputString
-          where
-            inputString = Data.Text.unpack line
-
-            outputString =
-                Text.Printf.printf ("%" <> show numberWidth <> "d: %s") n inputString
-
-        numberedLines = Data.Text.unlines (zipWith adapt [minimumNumber..] ls)
-
 {-| A `Parser` that is almost identical to
     @"Text.Megaparsec".`Text.Megaparsec.Parsec`@ except treating Haskell-style
     comments as whitespace
@@ -138,8 +98,10 @@
     Parser n >>= k = Parser (n >>= unParser . k)
     {-# INLINE (>>=) #-}
 
+#if !(MIN_VERSION_base(4,13,0))
     fail = Control.Monad.Fail.fail
     {-# INLINE fail #-}
+#endif
 
 instance Control.Monad.Fail.MonadFail Parser where
     fail = Parser . Control.Monad.Fail.fail
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
@@ -15,6 +15,7 @@
 import Data.Semigroup (Semigroup(..))
 import Data.Text (Text)
 import Dhall.Core
+import Dhall.Src (Src(..))
 import Prelude hiding (const, pi)
 import Text.Parser.Combinators (choice, try, (<?>))
 
@@ -247,9 +248,18 @@
     selectorExpression = noted (do
             a <- primitiveExpression
 
-            let left  x  e = Field   e x
-            let right xs e = Project e xs
-            b <- Text.Megaparsec.many (try (do _dot; fmap left anyLabel <|> fmap right labels))
+            let recordType = _openParens *> expression <* _closeParens
+
+            let field               x  e = Field   e  x
+            let projectBySet        xs e = Project e (Left  xs)
+            let projectByExpression xs e = Project e (Right xs)
+
+            let alternatives =
+                        fmap field               anyLabel
+                    <|> fmap projectBySet        labels
+                    <|> fmap projectByExpression recordType
+
+            b <- Text.Megaparsec.many (try (do _dot; alternatives))
             return (foldl (\e k -> k e) a b) )
 
     primitiveExpression =
@@ -660,24 +670,24 @@
   where
     parentPath = do
         _    <- ".." :: Parser Text
-        file <- file_
+        file <- file_ FileComponent
 
         return (Local Parent file)
 
     herePath = do
         _    <- "." :: Parser Text
-        file <- file_
+        file <- file_ FileComponent
 
         return (Local Here file)
 
     homePath = do
         _    <- "~" :: Parser Text
-        file <- file_
+        file <- file_ FileComponent
 
         return (Local Home file)
 
     absolutePath = do
-        file <- file_
+        file <- file_ FileComponent
 
         return (Local Absolute file)
 
@@ -693,7 +703,7 @@
     whitespace
     headers <- optional (do
         _using
-        (importHashed_ <|> (_openParens *> importHashed_ <* _closeParens)) )
+        (completeExpression import_ <|> (_openParens *> completeExpression import_ <* _closeParens)) )
     return (Remote (url { headers }))
 
 missing :: Parser ImportType
@@ -778,10 +788,16 @@
 unlinesLiteral chunks =
     Data.Foldable.fold (Data.List.NonEmpty.intersperse "\n" chunks)
 
-leadingSpaces :: Chunks s a -> Int
-leadingSpaces chunks =
-    Data.Text.length (Data.Text.takeWhile Data.Char.isSpace firstText)
+emptyLine :: Chunks s a -> Bool
+emptyLine (Chunks [] ""  ) = True
+emptyLine (Chunks [] "\r") = True  -- So that `\r\n` is treated as a blank line
+emptyLine  _               = False
+
+leadingSpaces :: Chunks s a -> Text
+leadingSpaces chunks = Data.Text.takeWhile isSpace firstText
   where
+    isSpace c = c == '\x20' || c == '\x09'
+
     firstText =
         case chunks of
             Chunks                []  suffix -> suffix
@@ -799,6 +815,26 @@
   where
     literals = linesLiteral literal
 
-    l :| ls = literals
+    sharedPrefix ab ac =
+        case Data.Text.commonPrefixes ab ac of
+            Just (a, _b, _c) -> a
+            Nothing          -> ""
 
-    indent = Data.Foldable.foldl' min (leadingSpaces l) (fmap leadingSpaces ls)
+    -- The standard specifies to filter out blank lines for all lines *except*
+    -- for the last line
+    filteredLines = newInit <> pure oldLast
+      where
+        oldInit = Data.List.NonEmpty.init literals
+
+        oldLast = Data.List.NonEmpty.last literals
+
+        newInit = filter (not . emptyLine) oldInit
+
+    longestSharedPrefix =
+        case filteredLines of
+            l : ls ->
+                Data.Foldable.foldl' sharedPrefix (leadingSpaces l) (fmap leadingSpaces ls)
+            [] ->
+                ""
+
+    indent = Data.Text.length longestSharedPrefix
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
@@ -6,6 +6,7 @@
     whitespace,
     bashEnvironmentVariable,
     posixEnvironmentVariable,
+    ComponentType(..),
     file_,
     label,
     anyLabel,
@@ -332,10 +333,25 @@
 
 posixEnvironmentVariableCharacter :: Parser Text
 posixEnvironmentVariableCharacter =
-    ("\\" <> satisfy predicate0) <|> satisfy predicate1
+    escapeCharacter <|> satisfy predicate1
   where
-    predicate0 c = c `elem` ("\"\\abfnrtv" :: String)
+    escapeCharacter = do
+        _ <- Text.Parser.Char.char '\\'
 
+        c <- Text.Parser.Char.satisfy (`elem` ("\"\\abfnrtv" :: String))
+
+        case c of
+            '"'  -> return "\""
+            '\\' -> return "\\"
+            'a'  -> return "\a"
+            'b'  -> return "\b"
+            'f'  -> return "\f"
+            'n'  -> return "\n"
+            'r'  -> return "\r"
+            't'  -> return "\t"
+            'v'  -> return "\v"
+            _    -> empty
+
     predicate1 c =
             ('\x20' <= c && c <= '\x21')
         ||  ('\x23' <= c && c <= '\x3C')
@@ -348,23 +364,31 @@
     ||  ('\x23' <= c && c <= '\x2E')
     ||  ('\x30' <= c && c <= '\x10FFFF')
 
-pathComponent :: Parser Text
-pathComponent = do
-    _      <- "/" :: Parser Text
+data ComponentType = URLComponent | FileComponent
 
-    let pathData = Text.Megaparsec.takeWhile1P Nothing Dhall.Core.pathCharacter
+pathComponent :: ComponentType -> Parser Text
+pathComponent componentType = do
+    _ <- "/" :: Parser Text
 
+    let pathData = do
+            text <- Text.Megaparsec.takeWhile1P Nothing Dhall.Core.pathCharacter
+
+            case componentType of
+                FileComponent -> return text
+                URLComponent  -> return (URI.Encode.decodeText text)
+
     let quotedPathData = do
             _    <- Text.Parser.Char.char '"'
             text <- Text.Megaparsec.takeWhile1P Nothing quotedPathCharacter
             _    <- Text.Parser.Char.char '"'
+
             return text
 
     pathData <|> quotedPathData
 
-file_ :: Parser File
-file_ = do
-    path <- Data.List.NonEmpty.some1 pathComponent
+file_ :: ComponentType -> Parser File
+file_ componentType = do
+    path <- Data.List.NonEmpty.some1 (pathComponent componentType)
 
     let directory = Directory (reverse (Data.List.NonEmpty.init path))
     let file      = Data.List.NonEmpty.last path
@@ -381,19 +405,9 @@
 httpRaw = do
     scheme    <- scheme_
     authority <- authority_
-    oldPath   <- file_
+    path      <- file_ URLComponent
     query     <- optional (("?" :: Parser Text) *> query_)
 
-    let path =
-            oldPath
-                { file = URI.Encode.decodeText (file oldPath)
-                , directory =
-                    (directory oldPath)
-                        { components =
-                            map URI.Encode.decodeText (components (directory oldPath))
-                        }
-                }
-
     let headers = Nothing
 
     return (URL {..})
@@ -441,28 +455,32 @@
     alternative2 = option h16 <> "::" <> count 4 (h16 <> ":") <> ls32
 
     alternative3 =
-            option (range 0 1 (h16 <> ":") <> h16)
+            option (h16 <> range 0 1 (try (":" <> h16)))
         <>  "::"
         <>  count 3 (h16 <> ":")
         <>  ls32
 
     alternative4 =
-            option (range 0 2 (h16 <> ":") <> h16)
+            option (h16 <> range 0 2 (try (":" <> h16)))
         <>  "::"
         <>  count 2 (h16 <> ":")
         <>  ls32
 
     alternative5 =
-        option (range 0 3 (h16 <> ":") <> h16) <> "::" <> h16 <> ":" <> ls32
+            option (h16 <> range 0 3 (try (":" <> h16)))
+        <>  "::"
+        <>  h16
+        <>  ":"
+        <>  ls32
 
     alternative6 =
-        option (range 0 4 (h16 <> ":") <> h16) <> "::" <> ls32
+        option (h16 <> range 0 4 (try (":" <> h16))) <> "::" <> ls32
 
     alternative7 =
-        option (range 0 5 (h16 <> ":") <> h16) <> "::" <> h16
+        option (h16 <> range 0 5 (try (":" <> h16))) <> "::" <> h16
 
     alternative8 =
-        option (range 0 6 (h16 <> ":") <> h16) <> "::"
+        option (h16 <> range 0 6 (try (":" <> h16))) <> "::"
 
 h16 :: Parser Text
 h16 = range 1 3 (satisfy hexdig)
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
@@ -732,8 +732,14 @@
     prettySelectorExpression :: Pretty a => Expr s a -> Doc Ann
     prettySelectorExpression (Field a b) =
         prettySelectorExpression a <> dot <> prettyAnyLabel b
-    prettySelectorExpression (Project a b) =
+    prettySelectorExpression (Project a (Left b)) =
         prettySelectorExpression a <> dot <> prettyLabels b
+    prettySelectorExpression (Project a (Right b)) =
+            prettySelectorExpression a
+        <>  dot
+        <>  lparen
+        <>  prettyExpression b
+        <>  rparen
     prettySelectorExpression (Note _ b) =
         prettySelectorExpression b
     prettySelectorExpression a0 =
diff --git a/src/Dhall/Repl.hs b/src/Dhall/Repl.hs
--- a/src/Dhall/Repl.hs
+++ b/src/Dhall/Repl.hs
@@ -251,6 +251,13 @@
 
 addBinding _ = Fail.fail ":let should be of the form `:let x = y`"
 
+clearBindings :: (MonadFail m, MonadState Env m) => [String] -> m ()
+clearBindings [] = modify adapt
+  where
+    adapt (Env {..}) = Env { envBindings = Dhall.Context.empty, ..}
+
+clearBindings _ = Fail.fail ":clear takes no arguments"
+
 hashBinding :: ( MonadFail m, MonadIO m, MonadState Env m ) => [String] -> m ()
 hashBinding [] = Fail.fail ":hash should be of the form `:hash expr"
 hashBinding tokens = do
@@ -415,6 +422,7 @@
   [ ( "type", dontCrash . typeOf )
   , ( "hash", dontCrash . hashBinding )
   , ( "let", dontCrash . addBinding . separateEqual )
+  , ( "clear", dontCrash . clearBindings)
   , ( "load", dontCrash . loadBinding )
   , ( "save", dontCrash . saveBinding . separateEqual )
   , ( "set", dontCrash . setOption)
diff --git a/src/Dhall/Src.hs b/src/Dhall/Src.hs
new file mode 100644
--- /dev/null
+++ b/src/Dhall/Src.hs
@@ -0,0 +1,60 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveGeneric      #-}
+{-# LANGUAGE OverloadedStrings  #-}
+
+-- | This module provides the `Src` type used for source spans in error messages
+
+module Dhall.Src
+    ( -- * Type
+      Src(..)
+    ) where
+
+import Data.Data (Data)
+import Data.Monoid ((<>))
+import Data.Text (Text)
+import Data.Text.Prettyprint.Doc  (Pretty (..))
+import GHC.Generics (Generic)
+import Text.Megaparsec (SourcePos)
+
+import {-# SOURCE #-} qualified Dhall.Util
+
+import qualified Data.Text       as Text
+import qualified Text.Megaparsec as Megaparsec
+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)
+
+instance Pretty Src where
+    pretty (Src begin _ text) =
+            pretty (Dhall.Util.snip numberedLines)
+        <>  "\n"
+        <>  pretty (Megaparsec.sourcePosPretty begin)
+      where
+        prefix = Text.replicate (n - 1) " "
+          where
+            n = Megaparsec.unPos (Megaparsec.sourceColumn begin)
+
+        ls = Text.lines (prefix <> text)
+
+        numberOfLines = length ls
+
+        minimumNumber =
+            Megaparsec.unPos (Megaparsec.sourceLine begin)
+
+        maximumNumber = minimumNumber + numberOfLines - 1
+
+        numberWidth :: Int
+        numberWidth =
+            truncate (logBase (10 :: Double) (fromIntegral maximumNumber)) + 1
+
+        adapt n line = Text.pack outputString
+          where
+            inputString = Text.unpack line
+
+            outputString =
+                Printf.printf ("%" <> show numberWidth <> "d: %s") n inputString
+
+        numberedLines = Text.unlines (zipWith adapt [minimumNumber..] ls)
diff --git a/src/Dhall/Tutorial.hs b/src/Dhall/Tutorial.hs
--- a/src/Dhall/Tutorial.hs
+++ b/src/Dhall/Tutorial.hs
@@ -65,6 +65,9 @@
     -- ** Caveats
     -- $caveats
 
+    -- ** Extending the language
+    -- $extending
+
     -- ** Overview
     -- $builtinOverview
 
@@ -1529,20 +1532,16 @@
 -- or you changed some of the imports and want to update the hashes you can use the
 -- freeze command to either add or update hashes:
 --
--- > cat foo.dhall
--- ''
--- let replicate =
---       https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate
---
--- in  replicate 5
--- ''
--- > dhall freeze --inplace ./foo.dhall
--- > cat ./foo.dhall
--- ''
--- let replicate =
---       https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate sha256:b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ad 
--- in  replicate 5
--- ''
+-- > $ cat foo.dhall
+-- > let replicate =
+-- >       https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate
+-- > in  replicate 5
+-- > $
+-- > $ dhall freeze --inplace ./foo.dhall
+-- > $ cat ./foo.dhall
+-- > let replicate =
+-- >       https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate sha256:b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ad
+-- > in  replicate 5
 --
 -- $rawText
 --
@@ -1819,6 +1818,92 @@
 --
 -- Second, the equality @(==)@ and inequality @(!=)@ operators only work on
 -- @Bool@s.  You cannot test any other types of values for equality.
+--
+-- However, you can extend the language with your own built-ins using the
+-- Haskell API, as described in the next section.
+
+-- $extending
+--
+-- You can use the Haskell API to extend the Dhall configuration language with
+-- new built-in functions.  This section contains a simple Haskell recipe to add
+-- a new @Natural/equal@ built-in function of type:
+--
+-- > Natural/equal : Natural → Natural → Bool
+--
+-- To do so, we:
+-- 
+-- * extend the type-checking context to include the type of @Natural/equal@
+-- * extend the normalizer to evaluate all occurrences of @Natural/equal@
+--
+-- ... like this:
+--
+-- > -- example.hs
+-- > 
+-- > {-# LANGUAGE OverloadedStrings #-}
+-- > 
+-- > module Main where
+-- > 
+-- > import Dhall.Core (Expr(..), ReifiedNormalizer(..))
+-- > 
+-- > import qualified Data.Text.IO
+-- > import qualified Dhall
+-- > import qualified Dhall.Context
+-- > import qualified Lens.Family   as Lens
+-- > 
+-- > main :: IO ()
+-- > main = do
+-- >     text <- Data.Text.IO.getContents
+-- > 
+-- >     let startingContext = transform Dhall.Context.empty
+-- >           where
+-- >             transform = Dhall.Context.insert "Natural/equal" naturalEqualType
+-- > 
+-- >             naturalEqualType =
+-- >                 Pi "_" Natural (Pi "_" Natural Bool)
+-- > 
+-- >     let normalizer (App (App (Var "Natural/equal") (NaturalLit x)) (NaturalLit y)) =
+-- >             Just (BoolLit (x == y))
+-- >         normalizer _ =
+-- >             Nothing
+-- > 
+-- >     let inputSettings = transform Dhall.defaultInputSettings
+-- >           where
+-- >             transform =
+-- >                   Lens.set Dhall.normalizer      (ReifiedNormalizer (pure . normalizer))
+-- >                 . Lens.set Dhall.startingContext startingContext
+-- > 
+-- >     x <- Dhall.inputWithSettings inputSettings Dhall.auto text
+-- > 
+-- >     Data.Text.IO.putStrLn x
+--
+-- Here is an example use of the above program:
+--
+-- > $ ./example <<< 'if Natural/equal 2 (1 + 1) then "Equal" else "Not equal"'
+-- > Equal
+--
+-- Note that existing Dhall tools that type-check expressions will reject
+-- expressions containing unexpected free variable such as @Natural/equal@:
+--
+-- > $ dhall <<< 'Natural/equal 2 (1 + 1)'
+-- > 
+-- > Use "dhall --explain" for detailed errors
+-- > 
+-- > Error: Unbound variable
+-- > 
+-- > Natural/equal 
+-- > 
+-- > (stdin):1:1
+--
+-- You will need to either:
+-- 
+-- * create your own parallel versions of these tools, or:
+-- * < https://github.com/dhall-lang/dhall-lang/blob/master/.github/CONTRIBUTING.md#how-do-i-change-the-language try to upstream your built-ins into the language>
+-- 
+-- The general guidelines for adding new built-ins to the language are:
+-- 
+-- * Keep built-ins easy to implement across language bindings
+-- * Prefer general purpose built-ins or built-ins appropriate for the task of program configuration
+-- * Design built-ins to catch errors as early as possible (i.e. when type-checking the configuration)
 
 -- $builtinOverview
 --
diff --git a/src/Dhall/TypeCheck.hs b/src/Dhall/TypeCheck.hs
--- a/src/Dhall/TypeCheck.hs
+++ b/src/Dhall/TypeCheck.hs
@@ -97,7 +97,7 @@
     constructor with custom logic
 -}
 typeWithA
-    :: Eq a
+    :: (Eq a, Pretty a)
     => Typer a
     -> Context (Expr s a)
     -> Expr s a
@@ -783,7 +783,7 @@
                 case Dhall.Map.lookup x kts of
                     Just t' -> return t'
                     Nothing -> Left (TypeError ctx e (MissingField x t))
-            Const Type -> do
+            _ -> do
                 case Dhall.Core.normalize r of
                   Union kts ->
                     case Dhall.Map.lookup x kts of
@@ -791,10 +791,9 @@
                         Just Nothing   -> return (Union kts)
                         Nothing -> Left (TypeError ctx e (MissingField x t))
                   r' -> Left (TypeError ctx e (CantAccess text r' t))
-            _ -> do
-                Left (TypeError ctx e (CantAccess text r t))
-    loop ctx e@(Project r xs    ) = do
+    loop ctx e@(Project r (Left xs)) = do
         t <- fmap Dhall.Core.normalize (loop ctx r)
+
         case t of
             Record kts -> do
                 _ <- loop ctx t
@@ -803,11 +802,39 @@
                         case Dhall.Map.lookup k kts of
                             Just t' -> return (k, t')
                             Nothing -> Left (TypeError ctx e (MissingField k t))
+
                 let adapt = Record . Dhall.Map.fromList
+
                 fmap adapt (traverse process (Dhall.Set.toList xs))
             _ -> do
-                let text = Dhall.Pretty.Internal.docToStrictText (Dhall.Pretty.Internal.prettyLabels xs)
+                let text =
+                        Dhall.Pretty.Internal.docToStrictText (Dhall.Pretty.Internal.prettyLabels xs)
+
                 Left (TypeError ctx e (CantProject text r t))
+    loop ctx e@(Project r (Right t)) = do
+        _R <- loop ctx r
+
+        case _R of
+            Record ktsR -> do
+                _ <- fmap Dhall.Core.normalize (loop ctx t)
+
+                case Dhall.Core.normalize t of
+                    Record ktsT -> do
+                        let keysR = Dhall.Set.fromList (Dhall.Map.keys ktsR)
+                        let keysT = Dhall.Set.fromList (Dhall.Map.keys ktsT)
+
+                        case Dhall.Set.difference keysT keysR of
+                            k : _ -> do
+                                Left (TypeError ctx e (MissingField k t))
+                            [] -> do
+                                return (Record ktsT)
+                    _ -> do
+                        Left (TypeError ctx e (CantProjectByExpression t))
+
+            _ -> do
+                let text = Dhall.Core.pretty t
+
+                Left (TypeError ctx e (CantProject text r t))
     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)
@@ -891,6 +918,7 @@
     | ConstructorsRequiresAUnionType (Expr s a) (Expr s a)
     | CantAccess Text (Expr s a) (Expr s a)
     | CantProject Text (Expr s a) (Expr s a)
+    | CantProjectByExpression (Expr s a)
     | MissingField Text (Expr s a)
     | CantAnd (Expr s a) (Expr s a)
     | CantOr (Expr s a) (Expr s a)
@@ -3406,7 +3434,7 @@
         \                                                                                \n\
         \────────────────────────────────────────────────────────────────────────────────\n\
         \                                                                                \n\
-        \You tried to access the fields:                                               \n\
+        \You tried to access the fields:                                                 \n\
         \                                                                                \n\
         \" <> txt0 <> "\n\
         \                                                                                \n\
@@ -3421,6 +3449,65 @@
         txt0 = insert lazyText0
         txt1 = insert expr0
         txt2 = insert expr1
+
+prettyTypeMessage (CantProjectByExpression expr) = ErrorMessages {..}
+  where
+    short = "Selector is not a record type"
+
+    long =
+        "Explanation: You can project by an expression if that expression is a record    \n\
+        \type:                                                                           \n\
+        \                                                                                \n\
+        \    ┌─────────────────────────────────┐                                         \n\
+        \    │ { foo = True }.({ foo : Bool }) │  This is valid ...                      \n\
+        \    └─────────────────────────────────┘                                         \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌──────────────────────────────────────────┐                                \n\
+        \    │ λ(r : { foo : Bool }) → r.{ foo : Bool } │  ... and so is this            \n\
+        \    └──────────────────────────────────────────┘                                \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \... but you cannot project by any other type of expression:                     \n\
+        \                                                                                \n\
+        \For example, the following expression is " <> _NOT <> " valid:                  \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌───────────────────────┐                                                   \n\
+        \    │ { foo = True }.(True) │                                                   \n\
+        \    └───────────────────────┘                                                   \n\
+        \                      ⇧                                                         \n\
+        \                      Invalid: Not a record type                                \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \Some common reasons why you might get this error:                               \n\
+        \                                                                                \n\
+        \● You accidentally try to project by a record value instead of a record type,   \n\
+        \  like this:                                                                    \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \    ┌─────────────────────────────────┐                                         \n\
+        \    │ let T = { foo : Bool }          │                                         \n\
+        \    │                                 │                                         \n\
+        \    │ let x = { foo = True , bar = 1} │                                         \n\
+        \    │                                 │                                         \n\
+        \    │ let y = { foo = False, bar = 2} │                                         \n\
+        \    │                                 │                                         \n\
+        \    │ in  x.(y)                       │                                         \n\
+        \    └─────────────────────────────────┘                                         \n\
+        \             ⇧                                                                  \n\
+        \             The user might have meant ❰T❱ here                                 \n\
+        \                                                                                \n\
+        \                                                                                \n\
+        \────────────────────────────────────────────────────────────────────────────────\n\
+        \                                                                                \n\
+        \You tried to project out the following type:                                    \n\
+        \                                                                                \n\
+        \" <> txt <> "\n\
+        \                                                                                \n\
+        \... which is not a record type                                                  \n"
+      where
+        txt = insert expr
 
 prettyTypeMessage (MissingField k expr0) = ErrorMessages {..}
   where
diff --git a/src/Dhall/Util.hs-boot b/src/Dhall/Util.hs-boot
new file mode 100644
--- /dev/null
+++ b/src/Dhall/Util.hs-boot
@@ -0,0 +1,5 @@
+module Dhall.Util where
+
+import Data.Text (Text)
+
+snip :: Text -> Text
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
@@ -4,6 +4,8 @@
 
 import Data.Monoid (mempty, (<>))
 import Data.Text (Text)
+import Dhall.Core (Expr, Import)
+import Dhall.TypeCheck (X)
 import Prelude hiding (FilePath)
 import Test.Tasty (TestTree)
 import Turtle (FilePath)
@@ -11,7 +13,6 @@
 import qualified Data.Text        as Text
 import qualified Data.Text.IO     as Text.IO
 import qualified Dhall.Core       as Core
-import qualified Dhall.Import     as Import
 import qualified Dhall.Lint       as Lint
 import qualified Dhall.Parser     as Parser
 import qualified Dhall.Test.Util  as Test.Util
@@ -40,17 +41,15 @@
 
         parsedInput <- Core.throws (Parser.exprFromText mempty inputText)
 
-        let lintedInput = Lint.lint parsedInput
-
-        actualExpression <- Import.load lintedInput
+        let actualExpression :: Expr X Import
+            actualExpression = Core.denote (Lint.lint parsedInput)
 
         outputText <- Text.IO.readFile outputFile
 
         parsedOutput <- Core.throws (Parser.exprFromText mempty outputText)
 
-        resolvedOutput <- Import.load parsedOutput
-
-        let expectedExpression = Core.denote resolvedOutput
+        let expectedExpression :: Expr X Import
+            expectedExpression = Core.denote parsedOutput
 
         let message = "The linted expression did not match the expected output"
 
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
@@ -41,7 +41,7 @@
 
     alphaNormalizationTests <- do
         Test.Util.discover pattern alphaNormalizationTest
-            Turtle.empty
+            (Turtle.lstree "./dhall-lang/tests/alpha-normalization/success/")
 
     let unitTestFiles = do
             path <- Turtle.lstree "./dhall-lang/tests/normalization/success/unit"
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
@@ -3,6 +3,8 @@
 module Dhall.Test.Parser where
 
 import Data.Text (Text)
+import Dhall.Core (Expr, Import)
+import Dhall.TypeCheck (X)
 import Prelude hiding (FilePath)
 import Test.Tasty (TestTree)
 import Turtle (FilePath, (</>))
@@ -23,17 +25,49 @@
 parseDirectory :: FilePath
 parseDirectory = "./dhall-lang/tests/parser"
 
+binaryDecodeDirectory :: FilePath
+binaryDecodeDirectory = "./dhall-lang/tests/binary-decode"
+
 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
+
     successTests <- do
-        Test.Util.discover (Turtle.chars <* "A.dhall") shouldParse (Turtle.lstree (parseDirectory </> "success"))
+        Test.Util.discover (Turtle.chars <* "A.dhall") shouldParse successFiles
 
     let failureFiles = do
             path <- Turtle.lstree (parseDirectory </> "failure")
 
             let skip =
-                    [ parseDirectory </> "failure/annotation.dhall"
+                    [ -- These two unexpected successes are due to not correctly
+                      -- requiring non-empty whitespace after the `:` in a type
+                      -- annotatoin
+                      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)
@@ -43,10 +77,17 @@
     failureTests <- do
         Test.Util.discover (Turtle.chars <> ".dhall") shouldNotParse failureFiles
 
+    let binaryDecodeFiles =
+            Turtle.lstree (binaryDecodeDirectory </> "success")
+
+    binaryDecodeTests <- do
+        Test.Util.discover (Turtle.chars <* "A.dhallb") shouldDecode binaryDecodeFiles
+
     let testTree =
             Tasty.testGroup "parser tests"
                 [ successTests
                 , failureTests
+                , binaryDecodeTests
                 ]
 
     return testTree
@@ -79,3 +120,26 @@
         case Parser.exprFromText mempty text of
             Left  _ -> return ()
             Right _ -> fail "Unexpected successful parser" )
+
+shouldDecode :: Text -> TestTree
+shouldDecode pathText = do
+    let pathString = Text.unpack pathText
+
+    Tasty.HUnit.testCase pathString (do
+        bytes <- ByteString.Lazy.readFile (pathString <> "A.dhallb")
+
+        term <- Core.throws (Serialise.deserialiseOrFail bytes)
+
+        decodedExpression <- Core.throws (Binary.decodeExpression term)
+
+        text <- Text.IO.readFile (pathString <> "B.dhall")
+
+        parsedExpression <- Core.throws (Parser.exprFromText mempty text)
+
+        let strippedExpression :: Expr X Import
+            strippedExpression = Core.denote parsedExpression
+
+        let message =
+                "The decoded expression didn't match the parsed expression"
+
+        Tasty.HUnit.assertEqual message decodedExpression strippedExpression )
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
@@ -26,12 +26,15 @@
     , URL(..)
     , Var(..)
     )
+
 import Dhall.Set (Set)
+import Dhall.Src (Src(..))
 import Numeric.Natural (Natural)
 import Test.QuickCheck
-    (Arbitrary(..), Gen, Property, genericShrink, (===), (==>))
+    (Arbitrary(..), Gen, Positive(..), Property, genericShrink, (===), (==>))
 import Test.QuickCheck.Instances ()
 import Test.Tasty (TestTree)
+import Text.Megaparsec (SourcePos(..), Pos)
 
 import qualified Codec.Serialise
 import qualified Data.Coerce
@@ -44,6 +47,7 @@
 import qualified Dhall.TypeCheck
 import qualified Test.QuickCheck
 import qualified Test.Tasty.QuickCheck
+import qualified Text.Megaparsec       as Megaparsec
 
 newtype DeserialiseFailureWithEq = D DeserialiseFailure
     deriving (Show)
@@ -261,6 +265,19 @@
     arbitrary = Test.QuickCheck.oneof [ pure Absolute, pure Here, pure Home ]
 
     shrink = genericShrink
+
+instance Arbitrary Src where
+    arbitrary = lift3 Src
+
+    shrink = genericShrink
+
+instance Arbitrary SourcePos where
+    arbitrary = lift3 SourcePos
+
+    shrink = genericShrink
+
+instance Arbitrary Pos where
+    arbitrary = lift1 (Megaparsec.mkPos . getPositive)
 
 instance Arbitrary ImportType where
     arbitrary =
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
@@ -2,11 +2,9 @@
 
 module Dhall.Test.TypeCheck where
 
+import Control.Exception (SomeException)
 import Data.Monoid (mempty, (<>))
 import Data.Text (Text)
-import Dhall.Import (Imported)
-import Dhall.Parser (Src)
-import Dhall.TypeCheck (TypeError, X)
 import Prelude hiding (FilePath)
 import Test.Tasty (TestTree)
 import Turtle (FilePath, (</>))
@@ -80,7 +78,7 @@
                 _ <- Import.load expression
                 return True
 
-        let handler :: Imported (TypeError Src X)-> IO Bool
+        let handler :: SomeException -> IO Bool
             handler _ = return False
 
         typeChecked <- Exception.handle handler io
