-
Notifications
You must be signed in to change notification settings - Fork 211
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
Proposal: Less heavy unions #163
Comments
Currently, the recommended approach is to define a constructor function for each alternative as either a $ cat ./A
λ(x : Integer) → < A = x | B : Bool | C : Text >
$ cat ./B
λ(x : Bool) → < A : Integer | B = x | C : Text >
$ cat ./C
λ(x : Text) → < A : Integer | B : Bool | C = x > ... and then you could use these constructors like this: [ ./A 1
, ./B True
, ./B False
, ./A 2
, ./C "ABC"
] If we were do to the same thing with let A = λ(x : Integer) → < A = x | B : Bool | C : Text >
in let B = λ(x : Bool) → < A : Integer | B = x | C : Text >
in let C = λ(x : Text) → < A : Integer | B : Bool | C = x >
in [ A 1
, B True
, B False
, A 2
, C "ABC"
] So that minimizes the overhead of union alternatives by only requiring you to write out the full union literal once (in the files or Out of the alternatives you proposed, the one I prefer is syntactic sugar for defining constructors. In other words, something like the following hypothetical syntax: data < A : Integer | B : Bool | C : Text >
in ... ... although perhaps the keyword data ./MySumType
in ... Also, for completeness I'll also address the strongest competing alternative you mentioned, which is open sums (a.k.a. polymorphic variants), since this question comes up frequently. I chose not to support open sums because of a broader policy to not support any form of subtyping. This is the same reason why Dhall uses explicit type-abstraction/type-application (since automatic specialization of polymorphic types is a form of subtyping) and this is also the same reason why Dhall does not support row polymorphism. The main reason why Dhall does not support subtyping is philosophical: Dhall is an experiment to see if a "fully functional" language is viable. "Fully functional" is a term I made up to denote the absence of logic-style programming at the type level (such as unification, resolving type class constraints, or checking refined types). I love Haskell, but one of my biggest criticisms of the Haskell language and ecosystem is that people seem "embarrassed" to use ordinary functional programming to solve problems and instead rely heavily on type-level Prolog to program. Dhall is basically a reaction to that to try to swing the pendulum back in the other direction to focus more on term-level functional programming. There are practical benefits to being fully functional, but the philosophical motivation is the core reason. The main practical benefits of being fully functional are:
|
Thank you for the detailed response! I already have a bit of Haskell code that exports dhall types for my Haskell records. Also, I've got beginnings of code that exports the constructors for unions types. Doing this with types not defined in Haskell feels bit inelegant, since generated and written dhall files have to be kept in sync manually. I fully appreciate the design philosophy but I would like to hear your opinions on the following two ideas: a)
Here, dhall would have syntactic sugar for naming a set of fields. The The negatives I can think of are, firstly that b)
In this idea, there is no syntactic sugar, but the type annotation would be integral part to sum literals. This would mirror the situation with Optional which requires a similar type annotation. On the downside this looks like an open sum but isn't. |
How about syntactic sugar for creating a record full of constructors? Something like:
Something like this would help a lot, but large and fully normalized sums are still absurdly verbose. |
@aleator: The problem with both proposals is that Dhall does not support Haskell-style type synonyms defined using let theSumType = <A:Nat | B:{} | C:{foo:Text,bar:Text}>
in ... ... would not work because Dhall's type-checker would not know that That in turns means that the only way you would be able to use this feature would be to import the type annotation from a path, but I would like this sum-type simplification feature to be usable without Dhall's import system. This is the reason I suggested a proposal that only requires specifying the type once because it sidesteps Dhall's limitations around repetitive types @benjamin-travis-summers: I like your proposal since it avoids cluttering the local namespace and it also doesn't technically require a
... and that would be legal Dhall code representing some record The other reason I like it is because it's way easier to implement @aleator: I think @benjamin-travis-summers's proposal would still be compatible with your use case, because you could still emit a single Dhall file containing the Dhall representation of your Haskell type, such as let MyHaskellType = SOMEKEYWORD ./MyHaskellType.dhall
in [ MyHaskellType.A +0, MyHaskellType.B {=}, ... ] I think the main thing that's left is deciding what
|
I think @benjamin-travis-summers suggestion would be sufficient for my use case. I still have slight doubt whether there could be something even nicer, but I can't think of anything. I vote for keyword |
So I will probably implement this using |
Fixes #163 This provides a new `constructors` keyword which can be used to create a record of constructors from a union type literal. The record contains one constructor per alternative in the union type.
Alright, I have a pull request out with support for the Let me know if that satisfies your use case |
I think it will work fine for me. |
Great! Also, thank you for requesting this feature :) |
This changes the standard semantics to support type synonyms, which is one of the most common feature requests. Here are some example requests: * dhall-lang/dhall-haskell#10 * dhall-lang/dhall-haskell#55 * dhall-lang/dhall-haskell#92 * dhall-lang/dhall-haskell#163 * dhall-lang/dhall-haskell#176 * dhall-lang/dhall-haskell#201 * #10 The change to the semantics is pretty simple: don't require that `let` expressions type-check as an equivalent anonymous function. Instead, just perform substitution and type-check the substituted expression. The semantics are still sound and this behaves the way users expect. For example, the following expression would be rejected before this change and accepted after this change: ```haskell let t = Integer in 1 : t ```
* Type synonym support This changes the standard semantics to support type synonyms, which is one of the most common feature requests. Here are some example requests: * dhall-lang/dhall-haskell#10 * dhall-lang/dhall-haskell#55 * dhall-lang/dhall-haskell#92 * dhall-lang/dhall-haskell#163 * dhall-lang/dhall-haskell#176 * dhall-lang/dhall-haskell#201 * #10 The change to the semantics is pretty simple: don't require that `let` expressions type-check as an equivalent anonymous function. Instead, just perform substitution and type-check the substituted expression. The semantics are still sound and this behaves the way users expect. For example, the following expression would be rejected before this change and accepted after this change: ```haskell let t = Integer in 1 : t ```
I find handling larger sum types a bit awkward. Consider for example
a simple 5-field sum. Each time a literal value is needed, one needs to enumerate
all the fields, which is, at minimum, this long:
This really doesn't encourage one to use larger sums. What I would like is a way to give a name for the 'other options' part. For example, I think it could be possible to do something like this
Or even,
which would mirror Optional.
Observing Dhall.Core, union literals are coded as
Where the second part is suspiciously similar to
So I would guess that implementing this would require extending the syntax a slight bit and allow mentioning the used sum-field in the list of alternatives.
Alternatively, one could consider:
The text was updated successfully, but these errors were encountered: