-
-
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 union alternatives without fields #438
Conversation
Fixes #224 This adds support for unions with empty alternatives that don't store any values. In the simple case where the union has all empty alternatives it degenerates to an enum. For example: ``` let Role = < Wizard | Fighter | Rogue > let show : Role → Text show = λ(x : Role) → merge { Wizard = "Wizard", Fighter = "Fighter", Rogue = "Rogue" } x in show Role.Wizard ``` However, these empty alternatives can be mixed with non-empty alternatives, too, with handlers to match: ``` let Status = < Empty | NonEmpty : Text > let concatSep : ∀(separator : Text) → ∀(elements : List Text) → Text = λ(separator : Text) → λ(elements : List Text) → let status = List/fold Text elements Status ( λ(element : Text) → λ(status : Status) → merge { Empty = Status.NonEmpty element , NonEmpty = λ(result : Text) → Status.NonEmpty (element ++ separator ++ result) } status ) Status.Empty in merge { Empty = "", NonEmpty = λ(result : Text) → result } status in concatSep ``` Handlers for empty alternatives no longer have to bind unused arguments of type `{}` and constructors for empty alternatives no longer have to take an input of `{=}`.
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.
Fantastic!
< x | xs₀… > ⇥ < x | xs₁… > | ||
|
||
|
||
The language still supports a deprecated union literal syntax for selecting one |
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.
Is the plan then to eventually normalize this syntax to the new syntax?
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.
@singpolyma: That's what I originally hoped, but the issue I ran into is that we can't (easily) do so because we don't have immediate access to the type of the selected alternative.
In other words, if we try to normalize < a = x >
to < a : T >.a x
we need to be able to infer the type T
of x
, but doing so would require interleaving type-checking and normalization.
It's still possible that dhall lint
might do this since it's fine if it's implementation is more complicated
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.
@Gabriel439 looks great! 👏
It's probably worth adding some parser and typecheck tests to verify that the new literal syntax also parses and typechecks correctly
@f-f: Yes, I've almost got the matching change to the Haskell implementation ready so that I can use it to generate additional golden test results |
In other words, if we try to normalize `< a = x >` to `< a : T >.a x` we need to be able to infer the type `T` of `x`, but doing so would require interleaving type-checking and normalization.
Ah, right, so we can require it in all cases. What about normalizing < a = (x : T) > to < a : T >.x -- this means that type annotating followed by normalizing would produce the desired result, at least.
|
@singpolyma: In my view, the main goal of normalizing the deprecated syntax to the newer syntax is so that lazy users don't have to migrate their code manually. If they have to provide a type annotation to take advantage of the migration then it feels to me like they don't benefit much because they could have instead migrated their code directly. However, I think in the common case most users won't need to migrate their code anyway because they are likely already using the |
A union constructor is now in normal form and does not normalize down to a λ-expression
... as standardized in dhall-lang/dhall-lang#438
Matching change to the Haskell implementation up here: dhall-lang/dhall-haskell#863 |
…dhall-lang into gabriel/nullary_alternatives
Projection is now in normal form after this change to how projection behaves
... as part of #438 I mistakenly changed the large expression binary test result, even though it did not need to be changed. I don't remember exactly what confusion of events led to me to computing the wrong golden test result while working on that change. This change reverts it back to where it was before.
... as part of #438 I mistakenly changed the large expression binary test result, even though it did not need to be changed. I don't remember exactly what confusion of events led to me to computing the wrong golden test result while working on that change. This change reverts it back to where it was before.
... as standardized in dhall-lang/dhall-lang#438 This also adds `dhall-json` support for empty alternatives In particular, this translates empty alternatives to strings encoding the alternative name ```haskell -- ./example.dhall let Role = < Wizard | Fighter | Rogue > in [ Role.Wizard, Role.Fighter ] ``` ``` $ dhall-to-json <<< './example.dhall' ["Wizard","Fighter"] ```
Fixes #224
This adds support for unions with empty alternatives that don't store any
values. In the simple case where the union has all empty alternatives it
degenerates to an enum.
For example:
However, these empty alternatives can be mixed with non-empty alternatives, too,
with handlers to match:
Handlers for empty alternatives no longer have to bind unused arguments of
type
{}
and constructors for empty alternatives no longer have to takean input of
{=}
.