[GHC] #9757: Warn about derivable instances

#9757: Warn about derivable instances -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Keywords: | Operating System: Architecture: Unknown/Multiple | Unknown/Multiple Difficulty: Unknown | Type of failure: Blocked By: | None/Unknown Related Tickets: | Test Case: | Blocking: | Differential Revisions: -------------------------------------+------------------------------------- GHC can derive a lot of instances by itself, and can sometimes (with `GeneralizedNewtypeDeriving`) do so better than anyone else. I'd like to be able to get a warning about any instance that's "obviously equivalent" to the one that would be derived, for some suitable values of "obviously" and "equivalent". -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9757 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9757: Warn about derivable instances -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: Type: feature | Status: new request | Milestone: Priority: normal | Version: 7.9 Component: Compiler | Keywords: Resolution: | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: | Related Tickets: None/Unknown | Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by goldfire): To my knowledge, GHC can ''not'' derive instances better than anyone else. Since the advent of `coerce`, `GeneralizedNewtypeDeriving` has no magic -- any GND instance can be written by hand, sometimes with lots of type annotations and `ScopedTypeVariables`, though. Personally, I would want to see nice definitions of "obviously" and "equivalent" before thinking too much harder about this. This seems hard to do and not terribly useful, to me. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9757#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9757: Warn about derivable instances -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: Type: feature | Status: new request | Milestone: Priority: normal | Version: 7.9 Component: Compiler | Keywords: Resolution: | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: | Related Tickets: None/Unknown | Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by dfeuer): Replying to [comment:1 goldfire]:
To my knowledge, GHC can ''not'' derive instances better than anyone else. Since the advent of `coerce`, `GeneralizedNewtypeDeriving` has no magic -- any GND instance can be written by hand, sometimes with lots of type annotations and `ScopedTypeVariables`, though.
I don't ''think'' this is exactly right. As I understand it, `coerce` should let you hand-build an exact ''copy'' of an existing dictionary, but `GeneralizedNewtypeDeriving` lets you actually ''reuse'' the dictionary.
Personally, I would want to see nice definitions of "obviously" and "equivalent" before thinking too much harder about this. This seems hard to do and not terribly useful, to me.
It's useful because GHC can derive a lot more things today than in olden times, and there's a lot of old code that hasn't noticed yet. The notion of "obviously" is to recognize plain wrap/unwrap patterns, preferably with enough flexibility to handle both pattern-matching versions and `(.)` versions and maybe even a little inlining. The scare quotes around "equivalent" were to recognize the potential for arity mismatches—a hand- written version may guarantee a certain arity that the GND-derived version does not. {{{#!hs newtype Foo m = Foo m instance Monoid m => Monoid Foo m where mempty = Foo mempty Foo x `mappend` Foo y = Foo (x `mappend` y) }}} I'd want this to be recognized as derivable even though it guarantees that `mappend _|_ = const _|_ /= _|_` while the GND-derived instance would not make such a guarantee. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9757#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9757: Warn about derivable instances -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: Type: feature | Status: new request | Milestone: Priority: normal | Version: 7.9 Component: Compiler | Keywords: Resolution: | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: | Related Tickets: None/Unknown | Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by goldfire): Replying to [comment:2 dfeuer]:
Replying to [comment:1 goldfire]:
To my knowledge, GHC can ''not'' derive instances better than anyone else. Since the advent of `coerce`, `GeneralizedNewtypeDeriving` has no magic -- any GND instance can be written by hand, sometimes with lots of type annotations and `ScopedTypeVariables`, though.
I don't ''think'' this is exactly right. As I understand it, `coerce` should let you hand-build an exact ''copy'' of an existing dictionary, but `GeneralizedNewtypeDeriving` lets you actually ''reuse'' the dictionary.
No, GND doesn't let you reuse dictionaries. Superclass instances might be different between the representation type and the newtype, and so reusing a dictionary might be wrong. GND builds a copy. (This surprised me, too, when I learned it.)
It's useful because GHC can derive a lot more things today than in olden times, and there's a lot of old code that hasn't noticed yet.
I still think this would be quite a bit of work and one more thing to maintain within GHC. The feature would also necessarily be heuristic in nature. It strikes me this would make a great feature in HLint, but I personally don't think GHC is the right home for it. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9757#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9757: Warn about derivable instances -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: Type: feature | Status: new request | Milestone: Priority: normal | Version: 7.9 Component: Compiler | Keywords: Resolution: | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: | Related Tickets: None/Unknown | Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by rwbarton): Thinking more about about this ticket and #9756, I think the purpose of compiler warnings should be to warn about code that is probably bad, not code that is probably fine that could be written in a (potentially) better way. (After all, we don't warn about excess parentheses in code either.) That is the domain of hlint, as Richard notes. Now #9756 is possibly an exception, if GHC is in a unique position to decide whether the replacement of `coerce` will type check, but I think the principle is a good one. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9757#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9757: Warn about derivable instances -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: Type: feature | Status: new request | Milestone: Priority: normal | Version: 7.9 Component: Compiler | Keywords: Resolution: | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: | Related Tickets: None/Unknown | Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by simonpj): I rather agree with Reid here. I.e. won't-fix. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9757#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9757: Warn about derivable instances -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: Type: feature | Status: closed request | Milestone: Priority: normal | Version: 7.9 Component: Compiler | Keywords: Resolution: wontfix | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: | Related Tickets: None/Unknown | Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Changes (by thomie): * status: new => closed * resolution: => wontfix Comment: Sorry David. Neil is usually very responsive to [https://github.com/ndmitchell/hlint issues and pull requests] though. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9757#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9757: Warn about derivable instances -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: Type: feature | Status: closed request | Milestone: Priority: normal | Version: 7.9 Component: Compiler | Keywords: Resolution: wontfix | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: | Related Tickets: None/Unknown | Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by NeilMitchell): Indeed, I'm certainly happy to discuss this on the HLint issue tracker. I think GHC warnings are generally general-purpose and clear issues (e.g. patterns are inexhaustive) while HLint ones can be more style-based and instance-specific (e.g. use notElem instead of not and elem). My guess is that it's probably impossible in any remotely general way to detect instances that would be better off done with generalised newtype deriving (and obviously actually impossible in the general case), but if anyone can come up with ideas/code I'd certainly consider it. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9757#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9757: Warn about derivable instances -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: Type: feature | Status: closed request | Milestone: Priority: normal | Version: 7.9 Component: Compiler | Keywords: Resolution: wontfix | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: | Related Tickets: None/Unknown | Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by goldfire): I'm not sure if this works with the way HLint is organized, but there is a decent way of detecting placing where GND can be used: take the Core produced from the instance definition of a newtype `N` (wrapping representation type `T`), strip out all coercions, and compare it against the Core for `T`'s instance. If each method in the instance for `N` is either a call to the method for `T`'s instance ''or'' symbol-for-symbol identical to `T`s instance, then GND is suitable. I think this algorithm would catch the common cases easily enough. But, like I said, I don't know how well looking at Core code matches with the way HLint normally goes about its business. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9757#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9757: Warn about derivable instances -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: Type: feature | Status: closed request | Milestone: Priority: normal | Version: 7.9 Component: Compiler | Keywords: Resolution: wontfix | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: | Related Tickets: None/Unknown | Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by NeilMitchell): HLint knows nothing about types, has no translation to Core and only has approximate information about name binding. Your approach seems feasible in GHC, and it might do a reasonable job, but wouldn't be suitable in HLint. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9757#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC