Function return type signatures#185
Conversation
Permit optional return-type signatures for top-level function definitions.
|
Ooh yes! Presumably this allows binding tyvars; where do constraints go?: Hmm. That's not pretty. But then neither is: The main motivation I see (I'm not coming from Scala/etc) is to avoid using |
|
Yes this would allow tyvars bound via pattern signatures as in your example, the only issue is that these are bound rigid (as discussed in the proposal). Thus we may want to permit an inline explicit forall somewhere as part of this proposal, or perhaps change the default binding behaviour for such pattern signatures under certain circumstances. Interestingly OCaml also requires explicit forall bindings for such inline signatures, if universal quantification is required. |
|
I believe there is already a proposal to relax the rigidity requirement. |
|
"Where do constraints go?" is a good question. I propose: nowhere. That is, if you want explicit constraints, write a top-level type signature. The ability to bind type variables in patterns is not new with this proposal, and the rigidity requirement seems orthogonal. If a user writes an inline signature such as this, is it considered a full signature? For example: Is that accepted? It needs a No one has given the type of Upshot to all this: if we consider any of these complete, then we're looking down the barrel of CUSKs, which have proven to be very confusing in type declarations. (Whether or not a type declaration is considered to have a complete type is defined by a somewhat-arbitrary set of syntactic hints.) I thus propose: no inline signature is considered complete. This means both that GHC would infer any constraints as necessary, and that polymorphic recursion would not be allowed with these signatures. By the way, I do think this would be a nice syntactic convenience. Thanks for writing it up. |
?So this proposal is not as conceptually simple as shunting the signature from the end of the rhs to the end of the lhs? Some personage is already complaining about the "veritable zoo of special cases". Is this going to be a different species of duck-billed platypus?
... or put the return signature on rhs. |
|
No, it is as simple as shunting the signature from the RHS to the LHS. You cannot add constraints to the type annotation of a RHS today, and you will not be able to add those same constraints on the LHS tomorrow. Using the above example, f (x :: a) = x + 1 :: ais not a complete type signature today, and GHC will infer the f (x :: a) = (if x == 0 then x else fromInteger (f (5 :: Integer)) + x) :: abecause that is only possible if there is a complete type signature. Instead, you must write f :: (Num a, Eq a) => a -> a
f (x :: a) = (if x == 0 then x else fromInteger (f (5 :: Integer)) + x) :: aSimilarly, f (x :: a) :: a = x + 1has no complete type signature, and the constraint must be inferred, as there is no place to write it, and, again f (x :: a) :: a = if x == 0 then x else fromInteger (f (5 :: Integer)) + xis rejected, as polymorphic recursion is a no-no. |
|
I can see that this proposal would sometimes be convenient; but I'm not sure that it fully pays its way. If adopted, I strongly urge that
Here the result signature brings
|
|
@AntC2 @goldfirere wrote the top-level signatures proposal, so I think that trac comment is just agreeing with @simonpj's point that we should have no more CUSKs. I'd like to emphasize that doing this proposal while not adding CUSKs not only avoids problems, but also makes the language more consistent in accordance with the top-level sigs proposal. Together the two would create near-complete "inline signatures" for all declaration types which I believe is a good thing to be consistent about: the user should need true top-level sigs for precisely signature completeness and not anything more (not being able to specify the return type otherwise) or less (there is some CUSK thing that also suffices). |
I'm confused. Yes for that signature, GHC infers the (I have no other signature for
Em, I seem to have put (That annotation looks weird. GHC infers I defer to the experts on whether such sigs should be considered complete/banning polymorphic recursion/CUSKs/etc. |
|
My "no place for constraints" comment is saying that there is no special place for constraints. This was confusing -- yes, you can put a constraint on the result type, and that works. But, placing this constraint does not turn off type inference, so it's unsurprising that GHC can infer a |
Good. Yes. Quite. Thank you for your "yes". I was getting too many "no"es -- I suspect in answer to questions I did not ask and did not intend and would not understand anyway. So please could the proposal include the following examples and say they're to be valid, so people can assess whether they're too weird/whether the extra syntax "pays its way": And point out that GHC is to infer With @nomeata's recent proposal to revive Then I suggest this proposal is enabled by |
|
Assuming my three suggestions above, there is a very big difference between The latter means That is, the is ill-typed. But I propose that is perfectly well typed. There is no automatic quantification (just as there isn't for patterns. Instead, the result type is constrained to be "something -> something" and These days, pattern-bound type variables can stand for types, not just type variables, so this is also ok Here with inferred type Putting any foralls or constraints on these pattern-bound types gets you into higher-rank types. Tricky territory. |
The former is not currently valid, so how can you claim what it means or what it's different from? What rule are you using? The proposal says that a return type sig on lhs is to mean the same as if it appeared on rhs. Treat that as purely syntactic sugar (to avoid the programmer repeating the sig on multiple rhs equations, and to show it more 'in your face').
Stop proposing. If a lhs sig is going to mean something different to a rhs, I see no merit here.
Does it? @goldfirere just said it doesn't. Or by "pattern-bound types" do you mean something different to this (with a constraint, but not taken as a "complete type signature"): You perhaps mean where a var is bound purely by a return type sig, not also bound to an argument? Then does it need a rule: return type signatures must not introduce variables? Please be clear. The proposal section 4 says
It's not clear from the text if this is only a description, or is intended as a prescription/restriction. |
Why should the meaning be the same? Type signatures in patterns bind type variables, type signatures in expressions introduce type variables. @simonpj argues that we should use the same principle for return type signatures, and it actually seems to have more merit: instead of a syntactic convenience, we get a way to bind variables in the result type. |
|
Now that we have https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0029-scoped-type-variables-types.rst, doing anything else would be neither consistent nor terribly useful. |
Because this proposal says that's what it wants, following the lead from other languages (section 2 to 3):
(You seem to be using a different sense of "consistent". I guess: what is consistent with which? I.e. not consistent in this sense:)
Then section 3's (and @howtonotwin's ) claims are false. Then this proposal is terrible and non-useful: kill it. |
It is consistent with the way
Since it's on the LHS of |
I don't get where the "terrible" claim comes from, but the "non-useful" is easy to counter: it becomes useful for everything that the proposal currently claims and for binding parts of the return type to type variables. |
|
cc: @goldfirere @simonpj This is just a side note related to this proposal to point out some related decisions in the design space. In dependently-typed programming, where GHC Haskell is moving towards to, it is often desired (although languages like Agda lack this) to let named arguments in types (to indicated term dependencies of types) to also be accessible in terms to avoid duplication. For example, in a dependent language, say Agda, we may have Notice the duplication in naming the arguments (the first naming is mandatory for stating the term dependency of types). How the above style interacts with induction / pattern matching is an important point to consider. |
|
So when do we allow data Ty :: Type
= TFree Name
| Ty :-> Ty |
|
Little activity recently, marking this as dormant. |
|
@timw-da Do you plan to submit this to the committee? |
|
Given the discussion so far, Digital Asset will reluctantly withdraw the proposal in its current form but would welcome any other contributors that might wish to take it forward. |
|
Ok, will close this, but encourage anyone who wants to pick it up again to reopen. |
|
Thanks for the information. I will write and submit my version of the proposal. |
|
The new proposal is at #228 |
This is a proposal to augment the existing
ScopedTypeVariablesextension to permit in-line function return type signatures, which are already recognised by the Happy grammar, but currently rejected. Such signatures can easily be given meaning and do permit very concise in-line type signature definitions.Rendered