-
Notifications
You must be signed in to change notification settings - Fork 266
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
Introduce -XTypeAbstractions, limiting -XScopedTypeVariables #238
Conversation
I agree with what's written here, except for one bit.
These emergent interactions between extensions aren't good. And what is left of Let's just accept #119 for |
Actually, this is not correct. Pattern signatures alone would not enable the expected scoping behavior:
Therefore, disregard my previous comment. I'm OK with the proposed amendment as is. |
Oh this is great! I preferred this design for aesthetic reasons anyways.
I do still like this idea. Is there precedent for one extension disabling part of another? I do generally like it when the set of extensions mapped to the set of accepted programs is monotonic. Perhaps a better argument is it would be nice to deprecate
That makes sense to me. I'd think one would have to write something along the lines of:
Likewise, I'd expect |
That's not equivalent, though. Compare:
|
That's already not true for a number of reasons. What is odd about this new proposal is that Of course, we could allow
So maybe that suggests this breakdown:
With this approach, a user could specify I would also favor coming up with a deprecation plan for |
I'm skeptical of supporting a configuration where Let's just roll with the current proposed amendment. |
Not really. What The code implementing |
What's the behavior of That it, does this code
get desugared into
and fail? It would work with the I need to know the full story, both for terms and types, to make progress on the implementation of TLKSs. I don't have too strong an opinion on the matter, but I'd like something simple rather than six extensions with intricate interplay between them ( Perhaps:
|
Gah. I'm lost again
OK so where is "the accepted proposal"?
There has to be an easier way than this to find the text of an accepted proposal! Plus, maybe this is a snapshot of the exact accepted propsoal, and Richard has a modified version. |
The accepted proposal and a rendered version of the update. Apologies that these were not more readily available. And I've updated the link in #155. |
I say But that's just my current opinion at the moment, and this all may yet evolve. |
What is the canonical way to do this? (Admittedly, this is a tangent to the main purpose of this ticket.) |
The more I think about the big-lambda proposal, the less I like it. This unexpected interaction with forall-scoping has taken me aback. Leave aside scoped type variables for the moment. Here are some questions.
I assume this is supposed to typecheck (but only if there is a signature!). But note that
Probably this is all do-able. But it's a change that potentially affects a lot of code, much more than I realised. What about pattern bindings? Am I allowed
I'm guessing not, but the proposal is silent. (Forall-scoping doesn't work for pattern bindings, incidentally.) I was on the fence about this big-lambda thing; now I'm mildly against. Esp as it only works in "checking mode", so it doesn't satisfy the "you can do System F" goal. We have so many other fish to fry, I rather wionder if we should park this one. (To mix metaphors.) |
I do expect there to be a non-trivial implementation burden, but I don't think the resulting code will be any worse (i.e. more complex) than what we have now. To implement type applications, we needed lazy instantiation. To implement type abstractions, we naturally need lazy skolemization. If you're bothered by the "checking" mode requirement, we could think harder about @gridaphobe's suggestion in the committee discussion:
I think that might work, but I'd want to draw some typing rules to be sure. Would that sway you? |
I think some typing rules would be a very good thing! I'm not dead set against this. I just feel uneasy. And that makes me wonder if we might be better spending our finite budget of intellectual cycles elsewhere, since this has turned out not to be the "quick win" that I initially thought it might be. |
I've updated the description of this proposal with a link to the rendered rich-text diff, which is pretty handy.
I think this suggests a useful addition to the protocol for accepting (or rejecting!) a proposal. The link at the time of discussion will point to the author's fork of this repo, which they might well update or delete in the future. We should update the "Rendered" link in the PR with a link to the permanent home of the proposal. This suggests that we ought to also keep a store of rejected proposals too for easy future reference. (ping @nomeata) I'm still pretty confused as well though. The proposal doesn't seem to explain what the problem is with having both
But this doesn't sound like a problem to me. It sounds like the Oh, there's also this sentence that I missed at first.
Why not? We allow shadowing at the term level, and also at the type level. This feels very much like shadowing to me. |
Thanks for pointing this out, I change the List of accepted proposal so something accurate (albeit less pretty). |
@goldfirere That's impossible, we don't have Λ in types. You seem to suggest that
maps to
and gets rejected for lack of Λ? Or do we map to |
ac73e98
to
0c18a86
Compare
About TLKSs: I say that having I have added some text to the proposal about why we can't have both. I was secretly hoping that vigorous waving of hands (and with an exclamation point!) would allay concerns, but I was rightly mistaken. |
In terms, we don't have to worry about the arity. I say we want the following code to be accepted:
And it's easy to make it accepted: map I think the rule in types should be:
"Other variables" are variables in TLKSs that cannot be instantiated due to the inferred arity, and variables outside TLKSs. This accepts more programs than the naive "just like it does in terms" rule. |
I think the TLKS issue was resolved elsewhere, and I'd like to return this conversation to the proposal at hand, which is concerned with the term-level, not the type level. Any further commentary before we go to committee? Thanks! |
@goldfirere what about your alternative with many more extensions? (Meta: how do alternatives go to the committee when an existing proposal is being amended?) |
In my comment above I asked about pattern bindings. The proposal remains silent. Could you add language to say what is supposed to happen? |
6b33e58
to
e7fdbc7
Compare
This needs attention from me, but I don't have attention to give this week. It is not abandoned, though. I shall return! (Next week, likely.) |
I'm not sure if this is the right place to put this, but after talking to @goldfirere I'll post my own motivation for this: https://stackoverflow.com/questions/50159349/type-abstraction-in-ghc-haskell {-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
module Foo where
f :: Int -> (forall f. Functor f => Secret f) -> Int
f x _ = x
g :: (forall f. Functor f => Secret f) -> Int
g = f 4
type family Secret (f :: * -> *) :: * where
Secret f = Int This (the binding for I'd really like this to become a thing, if only for reasons of symmetry with |
@cdsmith Hopefully this new version -- which does not gut Separately, I'm not exactly sure what you're asking about, above. Perhaps this will help: in the expression |
(I'm reading this proposal for the first time a bit late, so I apologize if I ask questions that have already been discussed.) I want to make sure that this proposal is able to encompass all of the use cases that currently require
As I understand it, I'm least sure about use case (1). The particular case of function declaration type signatures is covered at length in this proposal, but there's surprisingly little in the way of pattern synonym declaration type signatures. For example, suppose I define a pattern synonym that uses pattern J :: forall a. a -> Maybe a
pattern J x <- Just (x :: a) Is it possible to convert this code over to use pattern J @a x <- Just (x :: a) However, the proposal only discusses the changes needed for the |
From the proposal:
Is there a reason not to allow
|
@goldfirere For my part, I'm happy with either of the two accommodations: adding Me earlier confusion was because I didn't realize that expression signatures bound variables with |
I am a bit surprised by the Is that a niche opinion or how might problems with that be different on the type level? |
There are some corners of Haskell-dom that "consider it harmful," but they are mostly driven by corporate-style programming where you must accommodate an ever-changing large-ish team. Such a situation incentivizes working with a niche but standardized subset of the language. I wouldn't say That said, the main reason for the "considered harmful" afaiu is that wildcards potentially pollute scope in hard-to-understand ways (especially when used with |
Forgive me if this is tangential to this proposal, but something that has always confused me is: why isn't the scoping behavior of
To me, this is the most intuitive meaning of the type signature on the first line, and it makes that type signature the "single source of truth" for the names of the types below. It seems like this is the situation that we are trying to replicate with |
@maralorn the |
@davidsd Originally the choice was I believe due to backwards comparability. But while I'm happy to discard that, i am still not terribly found of automatic free variable binding like that. It is quite fragile, and all the more so when the variables are bound with a larger scope. Note with this proposal id :: a -> a
id @(..) x = (x :: a) will work, so you can skip the |
@Ericson2314 Could you give an example of what you mean by fragile? Often when editing a function, I realize I need access to one of the type variables in the arguments. I then have to scroll up to the type signature and add Under this proposal, What I really want almost 100% of the time is the ability to access type variables from the type signature in the body of my functions. (By the way, I am not trying to argue against the main motivating examples of this proposal, such as |
This is, indeed, a bit annoying. It's the combination of the forall-or-nothing rule (which makes perfect sense without scoped type variables) with the unfortunate second use of At the risk of too much piling on random ideas, I think it would be awesome to have something like (There are some subtleties: This should work for all type variables, regardless of their explicitness. It probably should not consume the argument, so that |
Pattern synonyms. Yes. Fixed now.
The whole reason inferred variables exist is because we cannot pin down their ordering. Allowing data Proxy a = MkProxy
f :: Proxy a -> Proxy b
f @{k} = ... What does the I personally find record puns questionable (though I still use them sometimes) for two reasons:
Neither problem occurs with this new syntax:
Yes, if we were happy to toss out backward compatibility, perhaps we would just always bring those type variables into scope. When I've programmed in dependently typed languages (that have a feature like the one I'm proposing here), I still sometimes wish the type variables just popped into scope without any effort. But Yes, I see the virtue in your @{m} construct. I'm not excited to have both mechanisms, though. Consider f :: forall a b. Bool -> a -> b -> ...
f @b True (x :: b) _ = ...
f @{b} True _ (y :: b) = ... In the two equations, the My bottom line here: yes, I agree that would be nice, but 1) I don't see a good way forward here and 2) the feature you want would be generally useful elsewhere, too, so it probably belongs in a separate proposal. |
Sure. I might argue that the similarity between |
I don't see how the proposal, as currently written, introduces even a short-term fork. This version is, I believe, compatible with today's Is there a forky aspect of what's here now that I'm missing? |
BTW, there is a conflict, I think because of the way the proposals were renumbered long ago to patch the PR numbers. |
I think this is ready to submit to the committee, @nomeata . |
I'm currently away from a laptop for 3 weeks, and while I could do the steps by email, it's a bit tedious. Maybe @serras can be going through the motions (label, assign, send mail to list), and either shepherd it yourself, or pick one of your liking. |
I am slightly delaying the process for this proposal, because it’s part or a growing jungle of proposals, and maybe we can do better: https://mail.haskell.org/pipermail/ghc-steering-committee/2021-August/002571.html |
Obliviated by #448 |
Recent discussion (on only tangentially related features) has brought to light that the accepted proposal for binding type variables does not fly. I have amended the proposal to fix the problem. Basically, we cannot have both
\ @a -> ...
and the scoping behavior offorall
. This new version introduces a new extension-XTypeAbstractions
that will control the new syntax, as well as disable the feature of-XScopedTypeVariables
that bringsforall
d variables into scope.Original, accepted proposal
Discussion on original proposal
Rendered new proposal