-
-
Notifications
You must be signed in to change notification settings - Fork 173
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
Add support for accessing/projecting record type fields #1371
base: master
Are you sure you want to change the base?
Conversation
… as standardized in dhall-lang/dhall-lang#1371
@@ -1514,7 +1514,7 @@ betaNormalize (RecordLiteral xts₀) = RecordLiteral xts₁ | |||
t₁ = betaNormalize t₀ | |||
``` | |||
|
|||
Simplify a record selection if the argument is a record literal: | |||
Simplify a record selection if the argument is a record literal or record type: | |||
|
|||
|
|||
t ⇥ { x = v, … } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This rule is for record literals. We also need a corresponding rule for record types here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
t ⇥ { x : T, … }
────────────────
t.x ⇥ T
@@ -1655,14 +1658,19 @@ You can also project out more than one field into a new record: | |||
t.{} ⇥ {=} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably need a rule where t
is a record type and then t.{} ⇥ {}
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems we need rules like this:
Γ ⊢ t : { ts… }
─────────── ; t is a record literal
t.{} ⇥ {=}
Γ ⊢ t : Type
───────── ; t is a record type
t.{} ⇥ {}
So, we need to type-check t
before beta-normalizing t.{}
. Until this change, beta-normalization never needed a type-checking phase but now it seems we have to introduce a dependency on type-checking. Also, it is not clear where Γ
would come from. How did you implement this in Haskell?
A test for this is to beta-normalize λ(x : { a : Bool }) → x.{}
, which should give λ(x : { a : Bool }) → {=}
. The beta-normalizer only looks at x.{}
and does not use the information about the declared type of x
. So, the beta-normalizer somehow needs to decide what to do with x.{}
without knowing the type of x
. Until now, only a record value x
was allowed. If we now allow also record types as x
, then we need to decide whether x.{}
reduces to {=}
or to {}
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One workaround is simply to disallow t.{}
in the type checker unless t
is a either a record value or a literal record type. Then we can first beta-normalize t.{...}
for literal record types t
, and if that does not match, then beta-normalize t.{} ⇥ {=}
for all t
without any checking.
This will disallow beta-normalizing t.{}
if t
is a variable carrying a record type but allow beta-normalizing t.{}
if t
is a variable carrying a record value, which is a bit ugly because it's asymmetric.
At the same time perhaps it is the right solution because we should not be beta-normalizing λ(t : Type) → t.{}
to λ(t : Type) → {}
really.
Another solution is a breaking change: delete the distinction between record types and record values; there will be just "records". Allow using the syntax { a = x, b = y}
and {a: x, b: y}
interchangeably. Then {a: Natural, b: Bool}
and {a = Natural, b = Bool}
will become the same term, and so will { a: 1, b: True}
and { a = 1, b = True}
. Records containing types will be used as types for records containing values:
{ a: 1, b: True} : {a: Natural, b: Bool}
or equivalently { a: 1, b: True} : {a = Natural, b = Bool}
This gets records closer to the Json syntax.
Typing will become trickier though. Currently, the type of {a = Bool}
is {a: Type}
while the type of {a : Bool}
is Type
.
Also, the syntax {=}
will become equivalent to {}
, which is perhaps a bad idea because we would like to distinguish them.
So, it seems that it's not really workable to conflate record values and record types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making record types and record values the same thing isn't feasible, because { a : Type, b : Type } /= Type
, so you would just have record “types” all the way down and never get to a universe. (I've thought a lot about this before.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that makes sense.
I have updated the description of the workaround I'm proposing.
Fixes #1079