-
Notifications
You must be signed in to change notification settings - Fork 697
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
Replace boilerplate Monoid/Semigroup instances with generics #3169
Comments
@23Skidoo the import Data.Semigroup
import GHC.Generics
-- | Generically generate a 'Semigroup' ('<>') operation for any type
-- implementing 'Generic'. This operation will append two values
-- by point-wise appending their component fields. It is only defined
-- for product types.
--
-- @
-- 'gmappend' a ('gmappend' b c) = 'gmappend' ('gmappend' a b) c
-- @
gmappend :: (Generic a, GSemigroup (Rep a)) => a -> a -> a
gmappend x y = to (gmappend' (from x) (from y))
class GSemigroup f where
gmappend' :: f p -> f p -> f p
instance GSemigroup U1 where
gmappend' _ _ = U1
instance GSemigroup V1 where
gmappend' x y = x `seq` y `seq` error "GSemigroup.V1: gmappend'"
instance Semigroup a => GSemigroup (K1 i a) where
gmappend' (K1 x) (K1 y) = K1 (x <> y)
instance GSemigroup f => GSemigroup (M1 i c f) where
gmappend' (M1 x) (M1 y) = M1 (gmappend' x y)
instance (GSemigroup f, GSemigroup g) => GSemigroup (f :*: g) where
gmappend' (x1 :*: x2) (y1 :*: y2) = gmappend' x1 y1 :*: gmappend' x2 y2
-- | Generically generate a 'Monoid' 'mempty' for any product-like type
-- implementing 'Generic'.
--
-- It is only defined for product types.
--
-- @
-- 'gmappend' 'gmempty' a = a = 'gmappend' a 'gmempty'
-- @
gmempty :: (Generic a, GMonoid (Rep a)) => a
gmempty = to gmempty'
class GSemigroup f => GMonoid f where
gmempty' :: f p
instance GMonoid U1 where
gmempty' = U1
instance (Semigroup a, Monoid a) => GMonoid (K1 i a) where
gmempty' = K1 mempty
instance GMonoid f => GMonoid (M1 i c f) where
gmempty' = M1 gmempty'
instance (GMonoid f, GMonoid g) => GMonoid (f :*: g) where
gmempty' = gmempty' :*: gmempty' |
@hvr Thanks! That link was just for reference in case someone wanted to tackle this ticket. |
@23Skidoo I've pushed some WIP changes to https://github.com/haskell/cabal/commits/wip/issue-3169 in case you want to take a peek... This results in the following diff-stats:
There's a huge block of boilerplate we could exterminate if the following FIXME was addressed:
This could be workarounded by moving the |
@dcoutts suggests to change the field to be that way we'd get a proper/less-hacky |
This implements the suggestions mentioned at #3169 (comment) The main benefit of this change is turning 'ConfigFlags' into a uniform product-type suitable for generic derivation of pointwise `Semigroup`/`Monoid` instances.
This implements the suggestions mentioned at #3169 (comment) The main benefit of this change is turning 'ConfigFlags' into a uniform product-type suitable for generic derivation of pointwise `Semigroup`/`Monoid` instances.
This implements the suggestions mentioned at haskell#3169 (comment) The main benefit of this change is turning 'ConfigFlags' into a uniform product-type suitable for generic derivation of pointwise `Semigroup`/`Monoid` instances. NB: This changes the `Binary` serialisation of `ConfigFlags` since there's now an additional `Maybe` inserted in `configPrograms`'s type
This implements the suggestions mentioned at haskell#3169 (comment) The main benefit of this change is turning 'ConfigFlags' into a uniform product-type suitable for generic derivation of pointwise `Semigroup`/`Monoid` instances. NB: This changes the `Binary` serialisation of `ConfigFlags` since there's now an additional `Maybe` inserted in `configPrograms`'s type
This implements the suggestions mentioned at haskell#3169 (comment) The main benefit of this change is turning 'ConfigFlags' into a uniform product-type suitable for generic derivation of pointwise `Semigroup`/`Monoid` instances. NB: This changes the `Binary` serialisation of `ConfigFlags` since there's now an additional `Maybe` inserted in `configPrograms`'s type
Add `gmappend`/`gmempty` Generics-helpers (re #3169)
👍 |
indeed... :-) |
This implements the suggestions mentioned at haskell#3169 (comment) The main benefit of this change is turning 'ConfigFlags' into a uniform product-type suitable for generic derivation of pointwise `Semigroup`/`Monoid` instances. NB: This changes the `Binary` serialisation of `ConfigFlags` since there's now an additional `Maybe` inserted in `configPrograms`'s type
For some reason I don't see a reference to #3193 here, so here it is. |
I've just updated the wip/issue-3169 branch; 19f2e5c now reports
|
BTW, it looks like Given the following definition:
Without
With
|
OK, looks like |
The types/casts this small example generates are nuts, however, I can see why generics increase compile time so much. |
@23Skidoo have you compared how more compact the resulting Core is compared to a manual definition instance Semigroup Foo where
a <> b = Foo { foo = combine foo
, bar = combine bar
, baz = combine baz
}
where combine field = field a `mappend` field b ? |
@hvr Well, if you look at the optimised Core I posted above, you'll see it's basically equivalent. |
I was looking at what GHC 8.0 generates with -O1 for the manual definition I gave above, and it's:
which looks less compact than what I get for the Generics based |
So I double-checked, and the following Haskell fragment:
generates the following Core with
This is with GHC 7.10.3. |
@hvr With 7.10
gives rise to
So it looks like they're the same. |
@23Skidoo ok, now I'm totally confused; even with GHC 7.10.3 I don't seem to get what you get: https://gist.github.com/hvr/cdc4996fde37814d1d10 |
|
This is preparatory work for implementing haskell#3169 it's kept in a different commit in order to facilitate comparing code-generation.
This increases compile-time (until GHC becomes more clever) but the generated code is expected to be at least as good (if not better) than the manually generated code. This addresses haskell#3169
This increases compile-time (until GHC becomes more clever) but the generated code is expected to be at least as good (if not better) than the manually generated code. This addresses haskell#3169
This is preparatory work for implementing haskell#3169 it's kept in a different commit in order to facilitate comparing code-generation.
This increases compile-time (until GHC becomes more clever) but the generated code is expected to be at least as good (if not better) than the manually generated code. This addresses haskell#3169
This increases compile-time (until GHC becomes more clever) but the generated code is expected to be at least as good (if not better) than the manually generated code. While at it, this removes -XCPP usage from all modules touched. This addresses haskell#3169
This increases compile-time (until GHC becomes more clever) but the generated code is expected to be at least as good (if not better) than the manually generated code. While at it, this removes -XCPP usage from all modules touched. This addresses haskell#3169
Turns out I was looking at unoptimised code. With |
This implements the suggestions mentioned at #3169 (comment) The main benefit of this change is turning 'ConfigFlags' into a uniform product-type suitable for generic derivation of pointwise `Semigroup`/`Monoid` instances. NB: This changes the `Binary` serialisation of `ConfigFlags` since there's now an additional `Maybe` inserted in `configPrograms`'s type (cherry picked from commit 62c3aa6)
This implements the suggestions mentioned at haskell#3169 (comment) The main benefit of this change is turning 'ConfigFlags' into a uniform product-type suitable for generic derivation of pointwise `Semigroup`/`Monoid` instances. NB: This changes the `Binary` serialisation of `ConfigFlags` since there's now an additional `Maybe` inserted in `configPrograms`'s type
This is preparatory work for implementing haskell#3169 it's kept in a different commit in order to facilitate comparing code-generation.
This is preparatory work for implementing haskell#3169 it's kept in a different commit in order to facilitate comparing code-generation.
This increases compile-time (until GHC becomes more clever) but the generated code is expected to be at least as good (if not better) than the manually generated code. This addresses haskell#3169
This increases compile-time (until GHC becomes more clever) but the generated code is expected to be at least as good (if not better) than the manually generated code. While at it, this removes -XCPP usage from all modules touched. This addresses haskell#3169
We have a large number of boilerplate
Monoid
/Semigroup
instances for large records inD.S.Setup
andD.C.Setup
(as well as in #3156). Those should be replaced with generics.Relevant Hackage package: https://hackage.haskell.org/package/generic-deriving-1.10.1/docs/Generics-Deriving-Monoid.html.
The text was updated successfully, but these errors were encountered: