Opened 6 years ago

Last modified 2 years ago

#8171 new feature request

Extending ExtendedDefaultRules

Reported by: ekmett Owned by:
Priority: normal Milestone:
Component: Compiler Version: 7.6.3
Keywords: ExtendedDefaultRules Cc: ekmett@…, ecrockett0@…, mentheta
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: #2641 Differential Rev(s):
Wiki Page:

Description (last modified by simonpj)

The current ExtendedDefaultRules (see manual page) is set up in a way that largely prevents it from being used for scenarios beyond what they get used for in GHCi today.

It would be great if there was an extra class that could be included in the list of acceptable classes for Rule 3.

class Defaulting a

The proposed change would be that Rule 3 under EDR can be be relaxed to: At least one of the classes Ci is numeric, or is Show, Eq, Ord or Defaulting.

I went with Defaulting rather than Default, because Default is a common class in use across the ecosystem from the data-default package, and I wanted to avoid gratuitous fallout.

This would permit projects like Shae Erisson's ghclive from last year that need to use defaulting to not have to shoe-horn unnecessary Show constraints onto functions.

Even better would be for that class to be polykinded!

That opens up possibilities for expert users to get defaulting to fire on arguments of other kinds, which is impossible under the current EDR.

Change History (14)

comment:1 Changed 6 years ago by ekmett

Cc: ekmett@… added

comment:2 Changed 6 years ago by simonpj

Description: modified (diff)

comment:3 Changed 6 years ago by simonpj

Would you like to elaborate a couple of use-cases? What types would be instances of Defaulting? Would one person's use of Defaulting mess up another's?

Simon

comment:4 Changed 6 years ago by ekmett

No more so than someone's instance of Show messing up another's.

Consider Shae Erisson's ghclive from last year's GSoC. There we're running a ghci analogue in the web browser, but we want to support doing things like rendering diagrams using Brent Yorgey's diagrams tool, so we have our own class of things we can show on the web.

class Display a where
    displayList :: [a] -> DisplayResult
    displayList = displayListOf display

    display :: a -> DisplayResult
    default display :: (Generic a, GDisplay (Rep a)) => a -> DisplayResult
    display = gdisplay . from

This is very much like Show, but it an include embedded images, hyperlinks, etc. as it is ultimately destined for the web.

We can tell hint to infer for it by wrapping whatever expression we get from the user in a call to display, but it won't do defaulting.

To fool hint into defaulting we have to add a completely unnecessary constraint to the environment to make the call elegible for defaulting! Of those, Show is the most innocuous, so we instead have to

displaying :: (Display a, Show a) => a -> DisplayResult
displaying = display

We then infer for it by wrapping the expression the user supplied in a 'displaying' call.

https://github.com/shapr/ghclive/blob/master/src-main/Main.hs#L214

But that is a lie. We don't need Show. We don't want Show. We just need to fake Show even for a number of un-Show-able things like diagrams to make GHC happy.

Worse, the displaying function used to have to be a separate function rather than be placed as a superclass of Display because GHC wouldn't rummage through the superclasses when figuring out if extended defaulting should fire, so we not only had to have an unnecessary Show constraint, but it had to be on the 'outside' of the current constraint set. That issue appears to have since been fixed though, so it should be possible with the addition of Defaulting to say:

class Defaulting a => Display a where

or to say the more targeted:

display :: (Display a, Defaulting a) => a -> DisplayResult

I'm open to other solutions. The instance seems somewhat clunky. In many ways maybe what you really kind of want is something like the roles annotations where you annotate the class arguments you want to allow defaulting on. That may be a way to address the current discussion about IsString, and could be a vehicle for enabling limited defaulting in the presence of MPTCs, but it was a lot more engineering effort than I felt comfortable asking for! =)

comment:5 Changed 6 years ago by simonpj

The extended-default rules for a bunch of constraints (C1 a1, C2 a2, ...) are these:

  1. The type variable a appears in no other constraints
  2. All of the classes Ci are single-parameter type classes.
  3. At least one of the classes Ci is numeric, or is Show, Eq, or Ord.

We could, I suppose, relax it by simply abolishing Rule 3. That would certainly solve your problem, and would require little engineering effort. I don't know what the unintended consequences might be.

comment:6 Changed 6 years ago by ekmett

Personally, I think that sounds like a pretty good fix.

I'd want to float it past the libraries mailing list to see what issues folks can foresee, but literally none of the packages I maintain on hackage would have an issue with this change, but you already get a warning with -Wall for defaulting, and all programs that typechecked before would necessarily continue to typecheck, more defaulting would work by default in future code though.

This interacts with the current libraries discussion on how to improve the rules about the shape of constraints (C1 a1, ...) to make it possible to support defaulting IsString when something like length "hello" on an OverloadedString happens.

With appropriate rephrasing of the conditions on the constraints above, we may be able to consolidate support both of these scenarios.

That said, I'm not sure off the top of my head how to rephrase that condition on the initial batch of constraints.

comment:7 Changed 6 years ago by simonpj

Fine with me. I just want to advertise that the EDR rules are not a deep property of type system. They are rather ad-hoc, driven by user need, and are modularly separated from the rest of type inference. So you are entirely free to propose different ones!

Simon

comment:8 Changed 6 years ago by ekmett

FWIW- We've been using a simpler system just like the one you proposed in our compiler for a Haskell-like language at work since its inception a couple of years ago with no user issues. We did so mostly because we couldn't be bothered to come up with a more complex system of rules.

https://github.com/ermine-language/ermine-legacy/blob/948a053b6f9ea274d11bf34cb2e3a9c7f3937923/src/main/scala/com/clarifi/reporting/ermine/Subst.scala#L382

comment:9 Changed 5 years ago by kanetw

Owner: set to kanetw

comment:10 Changed 5 years ago by kanetw

I'll be taking a look at this.

Last edited 5 years ago by kanetw (previous) (diff)

comment:11 Changed 4 years ago by kanetw

Owner: kanetw deleted

Currently don't have the time for this, but I might revisit this later.

comment:12 in reply to:  5 Changed 4 years ago by thomie

Keywords: ExtendedDefaultRules added

Replying to simonpj:

The extended-default rules for a bunch of constraints (C1 a1, C2 a2, ...) are these:

  1. The type variable a appears in no other constraints
  2. All of the classes Ci are single-parameter type classes.
  3. At least one of the classes Ci is numeric, or is Show, Eq, or Ord.

We could, I suppose, relax it by simply abolishing Rule 3.

See also #2641 (still open), where you proposed to make these rules less liberal, albeit 7 years ago.

comment:13 Changed 3 years ago by crockeea

Cc: ecrockett0@… added

Also see #12271. My primary concern there is GHC rather than GHCi. My main point there is: users should be able to specify defaults for user-defined/non-Prelude constraints; defaulting should not be a magical property baked into specific Prelude typeclasses.

It sounds like the solution proposed here would require -XEDR, whereas my proposed solution just modifies the existing default tuple, similar to what Edward suggested at the end of comment 4. I think removing rule 3 from the EDRs would effectively remove the "magic" that I talk about in that ticket.

comment:14 Changed 2 years ago by mentheta

Cc: mentheta added
Note: See TracTickets for help on using tickets.