Skip to content

Commit

Permalink
Add support for let expressions with multiple let bindings (#266)
Browse files Browse the repository at this point in the history
Fixes #260

In other words, this is now legal:

```haskell
let x = 1
let y = 2
in  x + y
```
  • Loading branch information
Gabriella439 committed Nov 8, 2018
1 parent 55475f7 commit 17f8a93
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 11 deletions.
3 changes: 2 additions & 1 deletion standard/dhall.abnf
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,8 @@ expression =

; "let x : t = e1 in e2"
; "let x = e1 in e2"
/ let label [ colon expression ] equal expression in expression
; "let x = e1 let y = e2 in e3"
/ 1*(let label [ colon expression ] equal expression) in expression

; "forall (x : a) -> b"
/ forall open-parens label colon expression close-parens arrow expression
Expand Down
169 changes: 159 additions & 10 deletions standard/semantics.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,10 @@ t : Naked label which could be any type of expression.
pairs. The specified alternative is named `xβ‚€ with
value of `tβ‚€`. At least one alternative is named
`x₁` with a type of `T₁`.
let xs… in b : A `let` definition with at least one bindings
let x : A = a let xs… in b : A `let` definition with at least two bindings
```

You will see this notation in judgments that perform induction on lists,
Expand Down Expand Up @@ -435,16 +439,32 @@ Descend as normal if the bound variable name does not match:
when descending past such a bound variable:


↑(d, x, m, Aβ‚€) = A₁ ↑(d, x, m, aβ‚€) = a₁ ↑(d, x, m + 1, bβ‚€) = b₁
───────────────────────────────────────────────────────────────────
↑(d, x, m, Aβ‚€) = A₁
↑(d, x, m, aβ‚€) = a₁
↑(d, x, m + 1, bβ‚€) = b₁
─────────────────────────────────────────────────────────
↑(d, x, m, let x : Aβ‚€ = aβ‚€ in bβ‚€) = let x : A₁ = a₁ in b₁


↑(d, x, m, aβ‚€) = a₁ ↑(d, x, m + 1, bβ‚€) = b₁
↑(d, x, m, aβ‚€) = a₁
↑(d, x, m + 1, bβ‚€) = b₁
───────────────────────────────────────────────
↑(d, x, m, let x = aβ‚€ in bβ‚€) = let x = a₁ in b₁


↑(d, x, m, Aβ‚€) = A₁
↑(d, x, m, aβ‚€) = a₁
↑(d, x, m + 1, let xs₀… in bβ‚€) = let xs₁… in b₁
───────────────────────────────────────────────────────────────────────────
↑(d, x, m, let x : Aβ‚€ = aβ‚€ let xs₀… in bβ‚€) = let x : A₁ = a₁ let xs₁… in b₁


↑(d, x, m, aβ‚€) = a₁
↑(d, x, m + 1, let xs₀… in bβ‚€) = let xs₁… in b₁
─────────────────────────────────────────────────────────────────
↑(d, x, m, let x = aβ‚€ let xs₀… in bβ‚€) = let x = a₁ let xs₁… in b₁


Again, the bound variable, `x`, is not in scope for its own type, `Aβ‚€`, so do
not increase the lower bound, `m`, when shifting the bound variable's type.

Expand All @@ -456,16 +476,33 @@ of the assignment.
Descend as normal if the bound variable name does not match:


↑(d, x, m, Aβ‚€) = A₁ ↑(d, x, m, aβ‚€) = a₁ ↑(d, x, m, bβ‚€) = b₁
─────────────────────────────────────────────────────────────── ; x β‰  y
↑(d, x, m, Aβ‚€) = A₁
↑(d, x, m, aβ‚€) = a₁
↑(d, x, m, bβ‚€) = b₁
───────────────────────────────────────────────────────── ; x β‰  y
↑(d, x, m, let y : Aβ‚€ = aβ‚€ in bβ‚€) = let y : A₁ = a₁ in b₁


↑(d, x, m, aβ‚€) = a₁ ↑(d, x, m, bβ‚€) = b₁
↑(d, x, m, aβ‚€) = a₁
↑(d, x, m, bβ‚€) = b₁
─────────────────────────────────────────────── ; x β‰  y
↑(d, x, m, let y = aβ‚€ in bβ‚€) = let y = a₁ in b₁


↑(d, x, m, Aβ‚€) = A₁
↑(d, x, m, aβ‚€) = a₁
↑(d, x, m, let ys₀… in bβ‚€) = let ys₁… in b₁
─────────────────────────────────────────────────────────────────────────── ; x β‰  y
↑(d, x, m, let y : Aβ‚€ = aβ‚€ let ys₀… in bβ‚€) = let y : A₁ = a₁ let ys₁… in b₁


↑(d, x, m, aβ‚€) = a₁
↑(d, x, m, bβ‚€) = b₁
↑(d, x, m, let ys₀… in bβ‚€) = let ys₁… in b₁
───────────────────────────────────────────────────────────────── ; x β‰  y
↑(d, x, m, let y = aβ‚€ let ys₀… in bβ‚€) = let y = a₁ let ys₁… in b₁


### Imports

You can shift expressions with unresolved imports because the language enforces
Expand Down Expand Up @@ -968,16 +1005,50 @@ All of the following rules cover expressions that can bind variables:
(let y : Aβ‚€ = aβ‚€ in bβ‚€)[x@n ≔ eβ‚€] = let y : A₁ = a₁ in b₁


aβ‚€[x@n ≔ eβ‚€] = a₁ ↑(1, x, 0, eβ‚€) = e₁ bβ‚€[x@(1 + n) ≔ e₁] = b₁
─────────────────────────────────────────────────────────────────
aβ‚€[x@n ≔ eβ‚€] = a₁
↑(1, x, 0, eβ‚€) = e₁
bβ‚€[x@(1 + n) ≔ e₁] = b₁
───────────────────────────────────────────────
(let x = aβ‚€ in bβ‚€)[x@n ≔ eβ‚€] = let x = a₁ in b₁


aβ‚€[x@n ≔ eβ‚€] = a₁ ↑(1, y, 0, eβ‚€) = e₁ bβ‚€[x@n ≔ e₁] = b₁
─────────────────────────────────────────────────────────── ; x β‰  y
aβ‚€[x@n ≔ eβ‚€] = a₁
↑(1, y, 0, eβ‚€) = e₁
bβ‚€[x@n ≔ e₁] = b₁
────────────────────────────────────────────── ; x β‰  y
(let y = aβ‚€ in bβ‚€)[x@n ≔ eβ‚€] = let y = a₁ in b₁


Aβ‚€[x@n ≔ eβ‚€] = A₁
aβ‚€[x@n ≔ eβ‚€] = a₁
↑(1, x, 0, eβ‚€) = e₁
(let xs₀… in bβ‚€)[x@(1 + n) ≔ e₁] = let xs₁… in b₁
───────────────────────────────────────────────────────────────────────────
(let x : Aβ‚€ = aβ‚€ let xs₀… in bβ‚€)[x@n ≔ eβ‚€] = let x : A₁ = a₁ let xs₁… in b₁


Aβ‚€[x@n ≔ eβ‚€] = A₁
aβ‚€[x@n ≔ eβ‚€] = a₁
↑(1, y, 0, eβ‚€) = e₁
(let xs₀… in bβ‚€)[x@n ≔ e₁] = let xs₁… in b₁
─────────────────────────────────────────────────────────────────────────── ; x β‰  y
(let y : Aβ‚€ = aβ‚€ let ys₀… in bβ‚€)[x@n ≔ eβ‚€] = let y : A₁ = a₁ let ys₁… in b₁


aβ‚€[x@n ≔ eβ‚€] = a₁
↑(1, x, 0, eβ‚€) = e₁
(let xs₀… in bβ‚€)[x@(1 + n) ≔ e₁] = let xs₁… in b₁
─────────────────────────────────────────────────────────────────
(let x = aβ‚€ let xs₀… in bβ‚€)[x@n ≔ eβ‚€] = let x = a₁ let xs₁… in b₁


aβ‚€[x@n ≔ eβ‚€] = a₁
↑(1, y, 0, eβ‚€) = e₁
(let ys₀… in bβ‚€)[x@n ≔ e₁] = let ys₁… in b₁
───────────────────────────────────────────────────────────────── ; x β‰  y
(let y = aβ‚€ let ys₀… in bβ‚€)[x@n ≔ eβ‚€] = let y = a₁ let ys₁… in b₁


### Imports

You can substitute expressions with unresolved imports because the language
Expand Down Expand Up @@ -1435,6 +1506,38 @@ capture:
let x = aβ‚€ in bβ‚€ ↦ let _ = a₁ in bβ‚„


aβ‚€ ↦ a₁
Aβ‚€ ↦ A₁
let xs₀… in bβ‚€ ↦ let xs₁… in b₁
───────────────────────────────────────────────────────────────
let _ = aβ‚€ : Aβ‚€ let xs₀… in bβ‚€ ↦ let _ = a₁ : A₁ let xs₁… in b₁


aβ‚€ ↦ a₁
Aβ‚€ ↦ A₁
↑(1, _, 0, bβ‚€) = b₁
b₁[x ≔ _] = bβ‚‚
↑(-1, x, 0, bβ‚‚) = b₃
let xs₀… in b₃ ↦ let xs₁… in bβ‚„
─────────────────────────────────────────────────────────────── x β‰  _
let x = aβ‚€ : Aβ‚€ let xs₀… in bβ‚€ ↦ let _ = a₁ : A₁ let xs₁… in bβ‚„


aβ‚€ ↦ a₁
let xs₀… in bβ‚€ ↦ let xs₁… in b₁
─────────────────────────────────────────────────────
let _ = aβ‚€ let xs₀… in bβ‚€ ↦ let _ = a₁ let xs₁… in b₁


aβ‚€ ↦ a₁
↑(1, _, 0, bβ‚€) = b₁
b₁[x ≔ _] = bβ‚‚
↑(-1, x, 0, bβ‚‚) = b₃
let xs₀… in b₃ ↦ let xs₁… in bβ‚„
───────────────────────────────────────────────────── x β‰  _
let x = aβ‚€ let xs₀… in bβ‚€ ↦ let _ = a₁ let xs₁… in bβ‚„


### Variables

Variables are already in Ξ±-normal form:
Expand Down Expand Up @@ -2999,6 +3102,26 @@ equivalence:
let x = aβ‚€ in bβ‚€ β‡₯ b₃


A `let` expression with multiple `let` bindings is equivalent to nested `let`
expressions:


↑(1, x, 0, aβ‚€) = a₁
(let xs… in bβ‚€)[x ≔ a₁] = b₁
↑(-1, x, 0, b₁) = bβ‚‚
bβ‚‚ β‡₯ b₃
─────────────────────────────────
let x : A = aβ‚€ let xs… in bβ‚€ β‡₯ b₃


↑(1, x, 0, aβ‚€) = a₁
(let xs… in bβ‚€)[x ≔ a₁] = b₁
↑(-1, x, 0, b₁) = bβ‚‚
bβ‚‚ β‡₯ b₃
─────────────────────────────
let x = aβ‚€ let xs… in bβ‚€ β‡₯ b₃


### Type annotations

Simplify a type annotation by removing the annotation:
Expand Down Expand Up @@ -4154,6 +4277,32 @@ expression would be well-typed.
If the `let` expression has a type annotation that doesn't match the type of
the right-hand side of the assignment then that is a type error.

A `let` expression with multiple `let` bindings is equivalent to nested `let`
expressions:


Ξ“ ⊒ aβ‚€ : A₁
Ξ“ ⊒ Aβ‚€ : i
Aβ‚€ ≑ A₁
aβ‚€ β‡₯ a₁
↑(1, x, 0, a₁) = aβ‚‚
(let xs… in bβ‚€)[x ≔ aβ‚‚] = b₁
↑(-1, x, 0, b₁) = bβ‚‚
Ξ“ ⊒ bβ‚‚ : B
─────────────────────────────────────
Ξ“ ⊒ let x : Aβ‚€ = aβ‚€ let xs… in bβ‚€ : B


Ξ“ ⊒ aβ‚€ : A
aβ‚€ β‡₯ a₁
↑(1, x, 0, a₁) = aβ‚‚
(let xs… in bβ‚€)[x ≔ aβ‚‚] = b₁
↑(-1, x, 0, b₁) = bβ‚‚
Ξ“ ⊒ bβ‚‚ : B
────────────────────────────────
Ξ“ ⊒ let x = aβ‚€ let xs… in bβ‚€ : B


### Type annotations

The inferred type of a type annotation is the annotation. Type-checking also
Expand Down

0 comments on commit 17f8a93

Please sign in to comment.