Exportable named defaults
As promised at the ICFP meeting. Here's the rendered proposal:
https://github.com/blamario/rfcs/blob/exportable-named-defaults/0000-exportable-named-defaults.rst
Several reactions:
-
There are a lot of moving parts to this proposal. It makes me worried to think about including this in the report without an implementation.
-
I've always found defaulting to be a bit dirty, and I'm dubious of making this facility this complicated.
-
I don't think this proposal is backward compatible, exactly as written: the new rules would prevent defaulting for a type like
Integral a => a -> aif there isn't adefault Integraldeclaration in scope. Note that the old rules allow subclasses ofNumbut the new ones don't.
There are a lot of moving parts to this proposal. It makes me worried to think about including this in the report without an implementation.
I would certainly welcome a implementation, but I'm not sure what the best way of effecting it would be. A GHC proposal would probably stand less efective.
I've always found defaulting to be a bit dirty, and I'm dubious of making this facility this complicated.
Call me unimaginative, but I see no way to make the proposal any simpler without making its practical use more complicated.
I don't think this proposal is backward compatible, exactly as written: the new rules would prevent defaulting for a type like Integral a => a -> a if there isn't a default Integral declaration in scope. Note that the old rules allow subclasses of Num but the new ones don't.
That was not my intent, but I can see how the proposal can be read that way. Sorry about the ambiguity. My mental picture of the constraint set C v for the type variable v was including all the super-classes of C. Thus, the constraint (Integral a) would be expanded to (Integral a, Num a, Enum a), which would then trigger the default declarations for all three classes.
Looking at the specification again, my understanding may be contradicted by section 4.5.2. I'll have to clarify the proposal. Nevertheless, the backward compatibility is maintained.
I would certainly welcome a implementation, but I'm not sure what the best way of effecting it would be. A GHC proposal would probably stand less efective.
I think it might work to present a proposal such as this one to the GHC committee, saying that the proposal is up for adoption into Haskell 2020. That would add weight to the proposal. It would still have to be accepted by the GHC committee, but I think it's appropriate that an unimplemented extension get more scrutiny than an established GHC extension. Perhaps we can even mark a proposal like this as "conditional accept", pending the results of the submission to the GHC committee and the experience learned through implementation.
Call me unimaginative, but I see no way to make the proposal any simpler without making its practical use more complicated.
I don't have a better suggestion.
That was not my intent, but I can see how the proposal can be read that way. Sorry about the ambiguity. My mental picture of the constraint set C v for the type variable v was including all the super-classes of C. Thus, the constraint (Integral a) would be expanded to (Integral a, Num a, Enum a), which would then trigger the default declarations for all three classes.
That's what I figured, but I wanted to point out this infelicity in the proposal as written.
Since the discussion so far has been quite clear and limited in scope, I decided to make the agreed adjustment to the existing pull request. It's only a clarification of intent.
https://github.com/haskell/rfcs/pull/18/commits/fa08a5f3fb931511a05c1163bfb31f947ba30cf2
When OverloadedStrings is left off, currently string literals are always String. This makes it harder to migrate away from String as the default in future versions of the standard.
We could reuse Naming The Class to allow users to specify what type string literals should have in this situation, by allowing exactly one type in sequences for IsString:
default IsString (Data.Text.Text) -- OK
default IsString (Data.Text.Text, String) -- Not OK
default IsString () -- Also not OK, as all string literals would be untypable
Imported defaults become more complicated in this case: I would suggest not importing defaults for IsString unless OverloadedStrings or something similar is on.
Similar could be done with OverloadedLists.