Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Record projection by expression #499

Merged
merged 21 commits into from
May 28, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
cd1e4f2
record projection by expression
dingxiangfei2009 Apr 21, 2019
db021b9
Merge branch 'master' of https://github.com/dhall-lang/dhall-lang int…
dingxiangfei2009 May 6, 2019
df19193
binary semantics
dingxiangfei2009 May 6, 2019
f5e109c
Merge branch 'master' of https://github.com/dhall-lang/dhall-lang int…
dingxiangfei2009 May 6, 2019
ae4a168
unit tests
dingxiangfei2009 May 6, 2019
f69e49b
fix unit tests
dingxiangfei2009 May 7, 2019
6185c96
switch tag from 19 to 9
dingxiangfei2009 May 8, 2019
4786493
remove extraneous type annotation
dingxiangfei2009 May 8, 2019
8bbd6fc
Merge branch 'master' of https://github.com/dhall-lang/dhall-lang int…
dingxiangfei2009 May 8, 2019
e340791
fix typo in beta normalization
dingxiangfei2009 May 12, 2019
d743135
Merge branch 'master' of https://github.com/dhall-lang/dhall-lang int…
dingxiangfei2009 May 12, 2019
2dfa774
switch tag number to 10; remove extra new lines
dingxiangfei2009 May 15, 2019
123ebc8
Merge branch 'master' into selector-extension
dingxiangfei2009 May 15, 2019
5c92ee8
remove redundant comment on record projection by type
dingxiangfei2009 May 15, 2019
e4d7928
fix type inference unit test
dingxiangfei2009 May 21, 2019
94cf52e
Merge branch 'master' of https://github.com/dhall-lang/dhall-lang int…
dingxiangfei2009 May 21, 2019
6f37451
Merge branch 'master' of https://github.com/dhall-lang/dhall-lang int…
dingxiangfei2009 May 22, 2019
3d43c8a
decoding judgement of projection; type inference rule by induction
dingxiangfei2009 May 23, 2019
1c07554
push the type projection one level down in CBOR encoding
dingxiangfei2009 May 26, 2019
0cc72ea
Merge branch 'master' of https://github.com/dhall-lang/dhall-lang int…
dingxiangfei2009 May 26, 2019
dedf45e
Merge branch 'master' into selector-extension
Gabriella439 May 28, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions standard/alpha-normalization.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,11 @@ sub-expressions for the remaining rules:
{ x = t₀, xs₀… } ↦ { x = t₁, xs₁… }


s₀ ↦ s₁ t₀ ↦ t₁
────────────────
s₀.(t₀) ↦ s₁.(t₁)


───────
<> ↦ <>

Expand Down
18 changes: 18 additions & 0 deletions standard/beta-normalization.md
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,24 @@ You can also project out more than one field into a new record:
t.{ x, xs… } ⇥ { x = v, ys… }


s ⇥ {}
──────────
t.(s) ⇥ {=}


t ⇥ { x = v, ts₀… }
s ⇥ { x : T, ts₀… }
Gabriella439 marked this conversation as resolved.
Show resolved Hide resolved
t.({ ss… }) ⇥ { ts₁… }
───────────────────────
t.(s) ⇥ { x = v, ts₁… }


t₀ ⇥ t₁
s₀ ⇥ s₁
───────────────── ; If no other rule matches
t₀.(s₀) ⇥ t₁.(s₁)


The type system ensures that the selected field(s) must be present.

Otherwise, normalize the argument:
Expand Down
16 changes: 16 additions & 0 deletions standard/binary.md
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,14 @@ Field access:
encode(t₀.{ x, y, … }) = [ 10, t₁, "x", "y", … ]


Record projection by type is encoded as follows:


encode(t₀) = t₁ encode(T₀) = T₁
Gabriella439 marked this conversation as resolved.
Show resolved Hide resolved
─────────────────────────────────
encode(t₀.(T₀)) = [ 19, t₁, T₁ ]


### Unions

Dhall union types translate to CBOR maps:
Expand Down Expand Up @@ -1199,6 +1207,14 @@ Decode a CBOR array beginning with a `10` as a record projection:
decode([ 10, t₁, "x", "y", … ]) = t₀.{ x, y, … }


Similarly, decode a CBOR array beginning with a `` as a record projection by type:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need this line at all, since the below (once switched to label 10) is just a second rule for the above decoding anyway.



decode(t₁) = t₀ decode(T₁) = T₀
─────────────────────────────────
decode([ 19, t₁, T₁]) = t₀.(T₀)


A decoder MUST NOT attempt to enforce uniqueness of keys. That is the
responsibility of the type-checking phase.

Expand Down
5 changes: 3 additions & 2 deletions standard/dhall.abnf
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ natural-literal = 1*DIGIT
integer-literal = ( "+" / "-" ) natural-literal

; If the identifier matches one of the names in the `builtin` rule, then it is a
; builtin, and should be treated as the curresponding item in the list of
; builtin, and should be treated as the corresponding item in the list of
; "Reserved identifiers for builtins" specified in the `semantics.md` document.
; It is a syntax error to specify a de Bruijn index in this case.
; Otherwise, this is a variable with name and index matching the label and index.
Expand Down Expand Up @@ -717,10 +717,11 @@ import-expression = import / selector-expression
; the function `foo` to the relative path `./bar`)
selector-expression = primitive-expression *(whsp "." whsp selector)

selector = any-label / labels
selector = any-label / labels / type-selector

labels = "{" whsp [ any-label whsp *("," whsp any-label whsp) ] "}"

type-selector = "(" whsp expression whsp ")"
; NOTE: Backtrack when parsing the first three alternatives (i.e. the numeric
; literals). This is because they share leading characters in common
primitive-expression =
Expand Down
7 changes: 7 additions & 0 deletions standard/type-inference.md
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,13 @@ You can only select field(s) from the record if they are present:
Γ ⊢ e :⇥ { x : T, ts… } Γ ⊢ { x : T, ts… } :⇥ Sort
────────────────────────────────────────────────────
Γ ⊢ e.{ x } : { x : T }


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add some prose here explaining that the e.(t) syntax lets the user select record fields by type. Currently there isn't any text in the standard explaining this feature

Γ ⊢ e :⇥ { ts… }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This judgment needs to somehow enforce that { ts… } and { ss… } are syntactically record types. One way to do that is define the judgment via induction (i.e. define a judgment to type-check the case where the two record types are empty and then define a judgment to type-check the case where the two record types are non-empty), like this:

Γ  e :⇥ {}
Γ  s : T
s  {}
────────────────
Γ  e.(s) : {}

Γ  e :⇥ { x : T₀,  }
Γ  s : T
s  { x : T₁, xs₁ }
Γ  e.({ xs₁ }) : T
────────────────────────
Γ  e.(s) : { x : T₁ ,xs₁ }

Copy link
Contributor Author

@dingxiangfei2009 dingxiangfei2009 May 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gabriel439 For the base case, we can relax the requirement on e, since it is still sound, in the same universe, to project empty record from any record.

Also, do you think that the following induction step make sense?

Γ ⊢ e :⇥ { x : T₀, ts… }
Γ ⊢ s : T₀
s ⇥ { x : T₀, ss… }
Γ ⊢ e.({ ss… }) : T₁
───────────────────────────
Γ ⊢ e.(s) : { x : T₀, ss… }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The concern is with the induction step that you suggested earlier, in which Γ ⊢ s : T and Γ ⊢ e.({ xs₁… }) : T cannot reconcile.

Copy link
Contributor

@Gabriella439 Gabriella439 May 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nadrieril: Oh yeah, the base case doesn't need to require that e is the empty record. That's a mistake on my part. Good catch!

Also, you're right that the two occurrences of T in the induction judgement should be distinct. That's another mistake on my part.

Γ ⊢ s : T
s ⇥ { ss… }
─────────────────────────────────────────── ; ss ⊆ ts
Γ ⊢ e.(s) : { ss… }


Γ ⊢ e :⇥ { x : T, ts₀… } Γ ⊢ e.{ xs… } :⇥ { ts₁… }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ a = 10, b = Some 10 }.({})
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{=}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing newline

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ a = 10, b = Some 10, c = [ "text" ]}.({ a : Natural, b : Optional Natural }) : { a : Natural, b : Optional Natural }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type annotation on the end here seems unneeded?

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ a = 10, b = Some 10 }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing newline

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dhall format automatically removes the new line when I add it.

15 changes: 15 additions & 0 deletions tests/parser/success/RecordProjectionByType.dhall
Original file line number Diff line number Diff line change
@@ -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 }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let e = { a = 10, b = "Text" } let s = { a : Natural } in e.(s) : { a : Natural }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be named A and have a B part with it -- the let seems like a lot of extra noise for a unit test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we should still have a test like this one, even if not necessarily for a unit test. It's important to test that type inference works when the s is an abstract type since that's a likely case that an implementation might implement incorrectly.