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
Exportable named defaults #409
Exportable named defaults #409
Conversation
85f70fb
to
928a86d
Compare
Thanks! The rendering is a bit off, maybe double-check the rst syntax (in particular for code blocks) |
Which code block do you have in mind? Or maybe you're thinking of a block quote instead? |
My bad, I only gave it a corsary look, and what looked like “bad code block” is actually “carefully constructed math” (the grammar rules). Ignore me :-) |
At @rae's suggestion, I'm bringing the proposal before the committee. |
To a degree, this kind of "fallback" is currently achievable with instance {-# INCOHERENT #-} s ~ String => IsString s where ... This isn't to say I'm pro- or anti- the proposal, but I'm interested in how the two behaviours would interact: if I have such an instance, and also a default, which one "wins" and when? I presume that, unlike the incoherence trick, providing a default instance wouldn't interfere with, say, |
I admit I've never seen this
The You can actually verify this today using the existing default declaration for
Exactly, no declared or inferred type would change. Also unlike the incoherence (or any other instance-based) trick, a |
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.
I'm on the fence about this proposal.
On the one hand, I'm sympathetic to the motivation. It would be nice to just import Data.Text
and have string literals default to Text
.
On the other hand, defaulting has always felt like a bit of a misfeature to me, and I'm not sure this proposal moves the needle. In particular, the design around explicit exports and module-local overrides feels in conflict with the global coherence of typeclass instances.
What if we instead required defaulting rules to be globally coherent? Your rule (4) for disambiguating multiple rules assumes that rules should be coherent. I think the main change to the proposal would be that default
rules would always be imported and exported, just like typeclass instances. I'm not sure this is the right design, maybe the way people think about defaulting rules isn't globally coherent, but it would be a conservative first step. We could always add the ability to selectively export and override defaulting rules later.
@blamario this proposal hasn't received much attention from the community. Have you advertised it? If not, I'd be happy to do so for you. I think it would be good to get more community feedback on this proposal. It address a real problem, but it's not clear to me how severe the problem is, and I expect that the break from the typeclass model of global coherence would be somewhat controversial. |
For better or worse,
That is a viable alternative to consider. I don't see it as a "conservative first step" though. It would not be backward compatible, if I understand what you're proposing correctly. The existing
I was of two minds about this extension. In the end I decided to add the extension in order to preserve full backward compatibility at the module level. I'm quite willing to make it the default behaviour, however, if others agree. It would certainly be a preferred candidate to add to the
I believe this is explained by the parenthetical remark in the same sentence. Your conclusion is correct.
Most Haskell code is free of ambiguous types, in my experience, so I wouldn't want to stop compiling if two imported defaults conflict but never need to be applied.
Correct. Okay, I will add a clarification. I'll also mention that the compiler should report a warning on conflicting imported defaults.
That's disturbing. Is prime.haskell.org gone for good?
That entirely depends on how much we value backward compatibility. If that's where we want to end up, we should start by warning if
Thank you, feel free to do it. I'm not good at advertising. |
It's a well-written proposal, and I can understand the motivation -- but it is (necessarily I think) somewhat complicated. It would take Real Work to implement, and maintain. For example, an exported default declaration I could be persuaded if there were many users for whom the existing Overall, like Eric, the proposal seems has clear merits, but I'm not sure it has enough power-to-weight ratio to make me want to implement it. |
I can add a discussion of the Can somebody with the knowledge clarify an undocumented point? The manual doesn't say whether the extension actually creates any new implicit While I'm at it, I'll also discuss the The reason both existing extensions (I hope there aren't more?) fall short is exactly because they are module-local, being easier to implement. They can't make |
I haven't read the proposal yet, but the other day I was thinking it might be nice to switch from talking about default instances to talking about default type arguments for functions. That way, for example, |
Why wouldn't they be exported from the
If you agree that it would be better to have
Ah right.
I'd probably model this after how we deal with conflicting class instances, which IIRC would mean no warning on import, but an error on use. The principle being that we shouldn't yell at a client module for something the library author did (break coherence).
I'd prefer the end state to be one with fewer special cases, even if it takes a while to get there :)
Done! I've posted to r/haskell and the Haskell Café. |
I have wished for this kind of extension many times. I wouldn't worry about global coherence; it's no worse than what we have today. In fact, I'd argue that we don't want coherence. |
I think that's entirely possible, but I don't have a concrete usecase, just a hunch that defaulting rules are a bit different from instances. Do you have a specific example in mind? |
I would really appreciate if you could list a few of them. I'm beginning to worry that if people concentrate only on the issue of |
…adedStrings, implicit ImportedDefaults alternative
+1 for NamedDefaults, but I'm a bit sceptical about |
Personally, I've been implementing a computational algebra system with much finer algebraic structures than the standard |
I am compiling all my packages with |
I'd love to be able to declare defaults for arbitrary classes, say example |
@simonpj ping, I'd still like you to take another look at the updated algorithm before accepting this proposal. |
I apologise. I have been 100.0% stalled because of my departure from MSR, so I have a massive backlog. And I'm giving to talks today. Next week, I promise -- yell at me if I don't deliver! |
/remind me to yell at @simonpj on 9/17 |
@gridaphobe set a reminder for Sep 17th 2021 |
👋 @gridaphobe, yell at @simonpj |
@simonpj ping! |
OK i have looked and made some suggestions. |
Where? |
Sorry I failed to press submit |
I'm sorry, I don't understand this comment. A type signature never invokes the defaulting process described in Section 2.5.
For example, when I call |
As I said: I guess I'm missing the picture of the overall type |
Let *S* be the complete set of unsolved constraints, and initialize *S*\ `x`:subscript: to an empty set of constraints. | ||
For every *v* that is free in *S*: | ||
|
||
1. Define *C*\ `v`:subscript: = { *C*\ `i`:subscript: v | *C*\ `i`:subscript: v ∈ *B*\ `v`:subscript: }, the subset 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.
Nearly. You want S rather than Bv here. (Bv isn't even defined.)
*C*\ `v`:subscript: | ||
3. Define *E*\ `v`:subscript:, by filtering *D*\ `v`:subscript: to contain only classes with a default declaration. | ||
4. For each *C*\ `i`:subscript: in *E*\ `v`:subscript:, find the first type *T*\ `i`:subscript: in the default list | ||
for *C*\ `i`:subscript: that satisfies all required constraints from the set *C*\ `v`:subscript:. |
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.
It'd be more precise to say "...for which, for every (Ci v) in Cv, the constraint (Ci T) is soluble".
(To avoid suffix confusion, I'd remove the "i" subscript from T.
@blamario thank you for your contribution! |
This proposal has been accepted; the following discussion is mostly of historic interest.