[PROPOSAL] Adding Generics-based DefaultSignature to `deepseq` package

Erik Hesselink hesselink at gmail.com
Thu Oct 16 15:30:36 UTC 2014


This reminds me of the default superclass instances proposals that
people are working on. I found three different ones on the GHC trac
[1,2,3].

Erik

[1] https://ghc.haskell.org/trac/ghc/wiki/DefaultSuperclassInstances
[2] https://ghc.haskell.org/trac/ghc/wiki/IntrinsicSuperclasses
[3] https://ghc.haskell.org/trac/ghc/wiki/InstanceTemplates


On Thu, Oct 16, 2014 at 5:03 PM, David Feuer <david.feuer at gmail.com> wrote:
> The important problem, as Edward Kmett would put it, is that Haskell is not
> good at dealing with lots of abstractions. In particular, making the
> typeclass hierarchy too fine-grained makes it painful to work with, because
> programmers have to satisfy the tower of superclass constraints in order to
> write an instance for a class. DefaultSignatures addresses this in a very
> limited way: If
>
> A a => B a => C a => D a
>
> then I may be able to give A, B, and C methods defaults with signatures so
> that I can declare an instance of D without needing to declare all the
> superclass instances. Unfortunately, this breaks down as soon as things
> branch:
>
> A a => B a => C a => D a
>
> ||
> V
>
> E a => F a => G a
>
> Both E and B may offer perfectly reasonable default definitions of a method
> in A, but I can only choose *one* of them. It also fails when class A is in
> someone else's module, and I'm doing a ton of work with subclasses of B and
> would like very much to add a default definition of a method in A, but
> simply can't. The current common use of DefaultSignatures is to use it
> *only* to provide defaults for Generic instances. While this single use-case
> works reasonably well, it effectively privileges Generic over everything
> else and leaves the general problem unsolved.
>
> The sort of general solution I'd hope for would probably look something
> vaguely like this, but I imagine the type gurus might see problems:
>
> Allow a *subclass* of a class to define (and override) default methods for
> the superclass. There is, of course, an immediate challenge: a single type
> could be a member of two subclasses, each of which defines a default for the
> same superclass method. The best solution I can think of to this is to
> require that such incoherent defaults be resolved manually by giving an
> explicit superclass instance declaration; ideally, that declaration would be
> able to access and choose from one of the available defaults, but that might
> be more trouble than it's worth.
>
> On Thu, Oct 16, 2014 at 10:39 AM, José Pedro Magalhães <dreixel at gmail.com>
> wrote:
>>
>> I'd like to know exactly what is the important problem, and how
>> DefaultSignatures are insufficiently general. Perhaps we can improve them,
>> or come up with something better!
>>
>> On Thu, Oct 16, 2014 at 2:36 PM, David Feuer <david.feuer at gmail.com>
>> wrote:
>>>
>>> I'm generally opposed to DefaultSignatures as an upside-down,
>>> insufficiently-general attempt to solve an important problem, and generally
>>> think the less relies on them the better.
>>>
>>> On Oct 16, 2014 6:40 AM, "Herbert Valerio Riedel" <hvr at gnu.org> wrote:
>>>>
>>>>
>>>> The Proposal
>>>> ============
>>>>
>>>> I hereby propose to merge `deepseq-generics`[2] into `deepseq`[1] in
>>>> order to add Generics support to the `NFData` class based on the
>>>> `-XDeriveGenerics` and `-XDefaultSignature` language extensions.
>>>>
>>>> A concrete patch is available for bike-review at [3]
>>>>
>>>>
>>>> Prior Proposal & What's changed
>>>> ===============================
>>>>
>>>> About 2 years ago, I already proposed something similar[4].  Back then
>>>> the major concern was avoiding a conditionally exported API as using the
>>>> (back then) rather young `Generics` extension would leave the Haskell98
>>>> domain.
>>>>
>>>> This lead to me release Generics support as a companion package[2] which
>>>> turns out to have become a rather popular package (judging from the
>>>> Hackage download-count stats).
>>>>
>>>> I only realized after the discussion was effectively finished, that
>>>> having a separate `deepseq-generics` actually does have an IMO
>>>> non-neglectable downside:
>>>>
>>>>   You can't support a `DefaultSignature`-based default implementation,
>>>> as those need to be backed into the `NFData` class.
>>>>
>>>> Missing out on `DefaultSignature` would be a shame IMO, because
>>>>
>>>>  * There's a chance that starting with GHC 7.10 `deriving` may work for
>>>>    arbitrary classes[5], putting `NFData` on equal footing as built-in
>>>>    classes such as `Eq` or `Show`. Specifically, you would be able to
>>>>    write
>>>>
>>>>       data Foo = Foo [Int] String (Bool,Char) | Bar (Maybe Char)
>>>>                  deriving (Show, Generic, NFData)
>>>>
>>>>    instead of having to manually write the following boilerplate
>>>>
>>>>       instance NFData Foo where
>>>>          rnf (Foo x y z) = rnf x `seq` rnf y `seq` rnf z
>>>>          rnf (Bar x)     = rnf x
>>>>
>>>>    which gets tedious rather soon if you have many (and more complex)
>>>>    types and tend to refactor regularly (with a risk of failing to adapt
>>>>    your manual instances if you change the strictness of fields)
>>>>
>>>>
>>>>  * The current default `rnf` implementation, i.e.
>>>>
>>>>      rnf a = a `seq` ()
>>>>
>>>>    is rather error-prone, as it's *very* easy to end up with an
>>>>    incorrect instance. Especially after refactoring a type for which the
>>>>    NF=WHNF assumption was broken after refactoring by adding new fields,
>>>>    or changing the strictness of existing fields.
>>>>
>>>>    The Generics-derived `rnf` implementation does not have such a
>>>>    problem.
>>>>
>>>>
>>>> Moreover, popular packages are starting adopt (and even recommend) the
>>>> use of Generics in combination with `DefaultSignature` to provide
>>>> automatically derived default instances, most notably `hashable`[6],
>>>> `binary`[7], or `aeson`[8] just to name a few. In addition to providing
>>>> a precedence for the use of Generics, I consider those packages evidence
>>>> for Generics to have proven itself to the point of replacing
>>>> TemplateHaskell in these use-cases.
>>>>
>>>>
>>>> Compatibility & Breakage Considerations
>>>> =======================================
>>>>
>>>>  * This change requires a major version bump to deepseq-1.4.0
>>>>
>>>>  * `deepseq` needs to drop GHC 7.0.* support as GHC 7.2 is the first
>>>>    version to support Generics & `DefaultSignature`.
>>>>
>>>>  * Code relying on the current `rnf` default-implementation will most
>>>>    likely break (unless a `Generics` instance happens to be in-place)
>>>>
>>>>    However, it's easy to provide forward/backward-compatibility w/o any
>>>>    CPP, by simply explicitly defining
>>>>
>>>>      instance NFData XYZ where rnf = seq x ()
>>>>
>>>>
>>>>
>>>> Discussion Period: 2 weeks
>>>>
>>>>
>>>>
>>>>  [1]: http://hackage.haskell.org/package/deepseq
>>>>  [2]: http://hackage.haskell.org/package/deepseq-generics
>>>>  [3]: https://github.com/haskell/deepseq/pull/1
>>>>  [4]: http://thread.gmane.org/gmane.comp.lang.haskell.libraries/17940
>>>>  [5]: https://ghc.haskell.org/trac/ghc/ticket/5462
>>>>  [6]: http://hackage.haskell.org/package/hashable
>>>>  [7]: http://hackage.haskell.org/package/binary
>>>>  [8]: http://hackage.haskell.org/package/aeson
>>>> _______________________________________________
>>>> Libraries mailing list
>>>> Libraries at haskell.org
>>>> http://www.haskell.org/mailman/listinfo/libraries
>>>
>>>
>>> _______________________________________________
>>> Libraries mailing list
>>> Libraries at haskell.org
>>> http://www.haskell.org/mailman/listinfo/libraries
>>>
>>
>
>
> _______________________________________________
> Libraries mailing list
> Libraries at haskell.org
> http://www.haskell.org/mailman/listinfo/libraries
>


More information about the Libraries mailing list