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

Add support for accessing/projecting record type fields #1371

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Gabriella439
Copy link
Contributor

Fixes #1079

Gabriella439 added a commit to dhall-lang/dhall-haskell that referenced this pull request Dec 3, 2023
@@ -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, … }
Copy link
Contributor

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.

Copy link
Contributor

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.{} ⇥ {=}
Copy link
Contributor

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.{} ⇥ {}?

Copy link
Contributor

@winitzki winitzki Dec 5, 2023

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 {}.

Copy link
Contributor

@winitzki winitzki Dec 5, 2023

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.

Copy link
Collaborator

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.)

Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Get field of record type using dot (.)
3 participants