packages feed

generic-data 0.2.0.0 → 0.3.0.0

raw patch · 7 files changed

+305/−40 lines, 7 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Generic.Data.Internal.Data: instance Generic.Data.Internal.Enum.GEnum r => GHC.Enum.Enum (Generic.Data.Internal.Data.Data r p)
- Generic.Data.Internal.Enum: instance (Generic.Data.Internal.Enum.GEnum f, Generic.Data.Internal.Enum.GEnum g) => Generic.Data.Internal.Enum.GEnum (f GHC.Generics.:+: g)
- Generic.Data.Internal.Enum: instance Generic.Data.Internal.Enum.GEnum GHC.Generics.U1
- Generic.Data.Internal.Enum: instance Generic.Data.Internal.Enum.GEnum f => Generic.Data.Internal.Enum.GEnum (GHC.Generics.M1 i c f)
- Generic.Data.Internal.Generically: instance (GHC.Generics.Generic a, Generic.Data.Internal.Enum.GEnum (GHC.Generics.Rep a)) => GHC.Enum.Enum (Generic.Data.Internal.Generically.Generically a)
+ Generic.Data: FiniteEnumeration :: a -> FiniteEnumeration a
+ Generic.Data: [unFiniteEnumeration] :: FiniteEnumeration a -> a
+ Generic.Data: data FiniteEnum
+ Generic.Data: data StandardEnum
+ Generic.Data: genumFrom :: (Generic a, GEnum StandardEnum (Rep a)) => a -> [a]
+ Generic.Data: genumFromThen :: (Generic a, GEnum StandardEnum (Rep a)) => a -> a -> [a]
+ Generic.Data: genumFromThenTo :: (Generic a, GEnum StandardEnum (Rep a)) => a -> a -> a -> [a]
+ Generic.Data: genumFromTo :: (Generic a, GEnum StandardEnum (Rep a)) => a -> a -> [a]
+ Generic.Data: gfiniteEnumFrom :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> [a]
+ Generic.Data: gfiniteEnumFromThen :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> a -> [a]
+ Generic.Data: gfiniteEnumFromThenTo :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> a -> a -> [a]
+ Generic.Data: gfiniteEnumFromTo :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> a -> [a]
+ Generic.Data: gfromFiniteEnum :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> Int
+ Generic.Data: gtoFiniteEnum :: forall a. (Generic a, GEnum FiniteEnum (Rep a)) => Int -> a
+ Generic.Data: newtype FiniteEnumeration a
+ Generic.Data.Internal.Data: instance Generic.Data.Internal.Enum.GEnum Generic.Data.Internal.Enum.StandardEnum r => GHC.Enum.Enum (Generic.Data.Internal.Data.Data r p)
+ Generic.Data.Internal.Enum: data FiniteEnum
+ Generic.Data.Internal.Enum: data StandardEnum
+ Generic.Data.Internal.Enum: genumFrom :: (Generic a, GEnum StandardEnum (Rep a)) => a -> [a]
+ Generic.Data.Internal.Enum: genumFrom' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> [a]
+ Generic.Data.Internal.Enum: genumFromThen :: (Generic a, GEnum StandardEnum (Rep a)) => a -> a -> [a]
+ Generic.Data.Internal.Enum: genumFromThen' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> a -> [a]
+ Generic.Data.Internal.Enum: genumFromThenTo :: (Generic a, GEnum StandardEnum (Rep a)) => a -> a -> a -> [a]
+ Generic.Data.Internal.Enum: genumFromThenTo' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> a -> a -> [a]
+ Generic.Data.Internal.Enum: genumFromTo :: (Generic a, GEnum StandardEnum (Rep a)) => a -> a -> [a]
+ Generic.Data.Internal.Enum: genumFromTo' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> a -> [a]
+ Generic.Data.Internal.Enum: genumMax :: forall opts a. (Generic a, GEnum opts (Rep a)) => Int
+ Generic.Data.Internal.Enum: genumMin :: Int
+ Generic.Data.Internal.Enum: gfiniteEnumFrom :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> [a]
+ Generic.Data.Internal.Enum: gfiniteEnumFromThen :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> a -> [a]
+ Generic.Data.Internal.Enum: gfiniteEnumFromThenTo :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> a -> a -> [a]
+ Generic.Data.Internal.Enum: gfiniteEnumFromTo :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> a -> [a]
+ Generic.Data.Internal.Enum: gfromEnum' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> Int
+ Generic.Data.Internal.Enum: gfromFiniteEnum :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> Int
+ Generic.Data.Internal.Enum: gtoEnum' :: forall opts a. (Generic a, GEnum opts (Rep a)) => String -> Int -> a
+ Generic.Data.Internal.Enum: gtoEnumRaw' :: forall opts a. (Generic a, GEnum opts (Rep a)) => Int -> a
+ Generic.Data.Internal.Enum: gtoFiniteEnum :: forall a. (Generic a, GEnum FiniteEnum (Rep a)) => Int -> a
+ Generic.Data.Internal.Enum: instance (GHC.Enum.Bounded c, GHC.Enum.Enum c) => Generic.Data.Internal.Enum.GEnum Generic.Data.Internal.Enum.FiniteEnum (GHC.Generics.K1 i c)
+ Generic.Data.Internal.Enum: instance (Generic.Data.Internal.Enum.GEnum Generic.Data.Internal.Enum.FiniteEnum f, Generic.Data.Internal.Enum.GEnum Generic.Data.Internal.Enum.FiniteEnum g) => Generic.Data.Internal.Enum.GEnum Generic.Data.Internal.Enum.FiniteEnum (f GHC.Generics.:*: g)
+ Generic.Data.Internal.Enum: instance (Generic.Data.Internal.Enum.GEnum opts f, Generic.Data.Internal.Enum.GEnum opts g) => Generic.Data.Internal.Enum.GEnum opts (f GHC.Generics.:+: g)
+ Generic.Data.Internal.Enum: instance Generic.Data.Internal.Enum.GEnum opts GHC.Generics.U1
+ Generic.Data.Internal.Enum: instance Generic.Data.Internal.Enum.GEnum opts f => Generic.Data.Internal.Enum.GEnum opts (GHC.Generics.M1 i c f)
+ Generic.Data.Internal.Generically: FiniteEnumeration :: a -> FiniteEnumeration a
+ Generic.Data.Internal.Generically: [unFiniteEnumeration] :: FiniteEnumeration a -> a
+ Generic.Data.Internal.Generically: instance (GHC.Generics.Generic a, Generic.Data.Internal.Enum.GEnum Generic.Data.Internal.Enum.FiniteEnum (GHC.Generics.Rep a)) => GHC.Enum.Enum (Generic.Data.Internal.Generically.FiniteEnumeration a)
+ Generic.Data.Internal.Generically: instance (GHC.Generics.Generic a, Generic.Data.Internal.Enum.GEnum Generic.Data.Internal.Enum.StandardEnum (GHC.Generics.Rep a)) => GHC.Enum.Enum (Generic.Data.Internal.Generically.Generically a)
+ Generic.Data.Internal.Generically: instance GHC.Generics.Generic a => GHC.Generics.Generic (Generic.Data.Internal.Generically.FiniteEnumeration a)
+ Generic.Data.Internal.Generically: newtype FiniteEnumeration a
- Generic.Data: class GEnum f
+ Generic.Data: class GEnum opts f
- Generic.Data: gfromEnum :: (Generic a, GEnum (Rep a)) => a -> Int
+ Generic.Data: gfromEnum :: (Generic a, GEnum StandardEnum (Rep a)) => a -> Int
- Generic.Data: gtoEnum :: forall a. (Generic a, GEnum (Rep a)) => Int -> a
+ Generic.Data: gtoEnum :: forall a. (Generic a, GEnum StandardEnum (Rep a)) => Int -> a
- Generic.Data.Internal.Enum: class GEnum f
+ Generic.Data.Internal.Enum: class GEnum opts f
- Generic.Data.Internal.Enum: gCardinality :: GEnum f => proxy f -> Int
+ Generic.Data.Internal.Enum: gCardinality :: GEnum opts f => Int
- Generic.Data.Internal.Enum: gFromEnum :: GEnum f => f p -> Int
+ Generic.Data.Internal.Enum: gFromEnum :: GEnum opts f => f p -> Int
- Generic.Data.Internal.Enum: gToEnum :: GEnum f => Int -> f p
+ Generic.Data.Internal.Enum: gToEnum :: GEnum opts f => Int -> f p
- Generic.Data.Internal.Enum: gfromEnum :: (Generic a, GEnum (Rep a)) => a -> Int
+ Generic.Data.Internal.Enum: gfromEnum :: (Generic a, GEnum StandardEnum (Rep a)) => a -> Int
- Generic.Data.Internal.Enum: gtoEnum :: forall a. (Generic a, GEnum (Rep a)) => Int -> a
+ Generic.Data.Internal.Enum: gtoEnum :: forall a. (Generic a, GEnum StandardEnum (Rep a)) => Int -> a

Files

CHANGELOG.md view
@@ -1,3 +1,11 @@+# 0.3.0.0++- Add generic implementations of `enumFrom`, `enumFromThen`, `enumFromTo`,+  `enumFromThenTo`. They are actually required to be explicit for correct+  `Enum` instances. Thanks to Topsii.+- Parameterize `GEnum` by a type-level option, and add `FiniteEnum` option+  to allow `Enum` to be derived for composite types. Thanks to Topsii.+ # 0.2.0.0  - Remove `Generic.Data.Types.Map`
generic-data.cabal view
@@ -1,5 +1,5 @@ name:                generic-data-version:             0.2.0.0+version:             0.3.0.0 synopsis:            Utilities for GHC.Generics description:         This package provides common functions on generic types.                      See README.
src/Generic/Data.hs view
@@ -36,10 +36,24 @@   , GShow0      -- ** 'Enum'+  , GEnum()+    -- *** StandardEnum option     -- | Can also be derived by GHC as part of the standard.-  , gfromEnum+  , StandardEnum()   , gtoEnum-  , GEnum()+  , gfromEnum+  , genumFrom+  , genumFromThen+  , genumFromTo+  , genumFromThenTo+    -- *** FiniteEnum option+  , FiniteEnum()+  , gtoFiniteEnum+  , gfromFiniteEnum+  , gfiniteEnumFrom+  , gfiniteEnumFromThen+  , gfiniteEnumFromTo+  , gfiniteEnumFromThenTo      -- ** 'Bounded'     -- | Can also be derived by GHC as part of the standard.@@ -90,6 +104,7 @@      -- * Carriers of generic instances   , Generically(..)+  , FiniteEnumeration(..)   , Generically1(..)      -- * Newtype
src/Generic/Data/Internal/Data.hs view
@@ -5,6 +5,7 @@ {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} @@ -54,9 +55,9 @@ instance GShow1 r => Show1 (Data r) where   liftShowsPrec = (fmap . fmap) (flip . (. unData)) gLiftPrecShows -instance GEnum r => Enum (Data r p) where-  toEnum = Data . gToEnum-  fromEnum = gFromEnum . unData+instance GEnum StandardEnum r => Enum (Data r p) where+  toEnum = Data . gToEnum @StandardEnum+  fromEnum = gFromEnum @StandardEnum . unData  instance GBounded r => Bounded (Data r p) where   minBound = Data gMinBound
src/Generic/Data/Internal/Enum.hs view
@@ -1,36 +1,166 @@+{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeOperators #-}  module Generic.Data.Internal.Enum where  import GHC.Generics-import Data.Proxy --- | Generic 'toEnum'.+-- | Generic 'toEnum' generated with the 'StandardEnum' option. -- -- @ -- instance 'Enum' MyType where --   'toEnum' = 'gtoEnum' --   'fromEnum' = 'gfromEnum'+--   'enumFrom' = 'genumFrom'+--   'enumFromThen' = 'genumFromThen'+--   'enumFromTo' = 'genumFromTo'+--   'enumFromThenTo' = 'genumFromThenTo' -- @-gtoEnum :: forall a. (Generic a, GEnum (Rep a)) => Int -> a-gtoEnum n-  | 0 <= n && n < card = to (gToEnum n)-  | otherwise = error $-      "gtoEnum: out of bounds, index " ++ show n ++ ", card " ++ show card-  where-    card = gCardinality (Proxy :: Proxy (Rep a))+gtoEnum :: forall a. (Generic a, GEnum StandardEnum (Rep a)) => Int -> a+gtoEnum = gtoEnum' @StandardEnum "gtoEnum" --- | Generic 'fromEnum'.+-- | Generic 'fromEnum' generated with the 'StandardEnum' option. -- -- See also 'gtoEnum'.-gfromEnum :: (Generic a, GEnum (Rep a)) => a -> Int-gfromEnum = gFromEnum . from+gfromEnum :: (Generic a, GEnum StandardEnum (Rep a)) => a -> Int+gfromEnum = gfromEnum' @StandardEnum +-- | Generic 'enumFrom' generated with the 'StandardEnum' option.+--+-- See also 'gtoEnum'.+genumFrom :: (Generic a, GEnum StandardEnum (Rep a)) => a -> [a]+genumFrom = genumFrom' @StandardEnum++-- | Generic 'enumFromThen' generated with the 'StandardEnum' option.+--+-- See also 'gtoEnum'.+genumFromThen :: (Generic a, GEnum StandardEnum (Rep a)) => a -> a -> [a]+genumFromThen = genumFromThen' @StandardEnum++-- | Generic 'enumFromTo' generated with the 'StandardEnum' option.+--+-- See also 'gtoEnum'.+genumFromTo :: (Generic a, GEnum StandardEnum (Rep a)) => a -> a -> [a]+genumFromTo = genumFromTo' @StandardEnum++-- | Generic 'enumFromThenTo' generated with the 'StandardEnum' option.+--+-- See also 'gtoEnum'.+genumFromThenTo :: (Generic a, GEnum StandardEnum (Rep a)) => a -> a -> a -> [a]+genumFromThenTo = genumFromThenTo' @StandardEnum+++-- | Generic 'toEnum' generated with the 'FiniteEnum' option.+--+-- @+-- instance 'Enum' MyType where+--   'toEnum' = 'gtoFiniteEnum'+--   'fromEnum' = 'gfromFiniteEnum'+--   'enumFrom' = 'gfiniteEnumFrom'+--   'enumFromThen' = 'gfiniteEnumFromThen'+--   'enumFromTo' = 'gfiniteEnumFromTo'+--   'enumFromThenTo' = 'gfiniteEnumFromThenTo'+-- @+gtoFiniteEnum :: forall a. (Generic a, GEnum FiniteEnum (Rep a)) => Int -> a+gtoFiniteEnum = gtoEnum' @FiniteEnum "gtoFiniteEnum"++-- | Generic 'fromEnum' generated with the 'FiniteEnum' option.+--+-- See also 'gtoFiniteEnum'.+gfromFiniteEnum :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> Int+gfromFiniteEnum = gfromEnum' @FiniteEnum++-- | Generic 'enumFrom' generated with the 'FiniteEnum' option.+--+-- See also 'gtoFiniteEnum'.+gfiniteEnumFrom :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> [a]+gfiniteEnumFrom = genumFrom' @FiniteEnum++-- | Generic 'enumFromThen' generated with the 'FiniteEnum' option.+--+-- See also 'gtoFiniteEnum'.+gfiniteEnumFromThen :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> a -> [a]+gfiniteEnumFromThen = genumFromThen' @FiniteEnum++-- | Generic 'enumFromTo' generated with the 'FiniteEnum' option.+--+-- See also 'gtoFiniteEnum'.+gfiniteEnumFromTo :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> a -> [a]+gfiniteEnumFromTo = genumFromTo' @FiniteEnum++-- | Generic 'enumFromThenTo' generated with the 'FiniteEnum' option.+--+-- See also 'gtoFiniteEnum'.+gfiniteEnumFromThenTo :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> a -> a -> [a]+gfiniteEnumFromThenTo = genumFromThenTo' @FiniteEnum++-- | Unsafe generic 'toEnum'. Does not check whether the argument is within+-- valid bounds. Use 'gtoEnum' or 'gtoFiniteEnum' instead.+gtoEnumRaw' :: forall opts a. (Generic a, GEnum opts (Rep a)) => Int -> a+gtoEnumRaw' = to . gToEnum @opts++-- | Generic 'toEnum'. Use 'gfromEnum' or 'gfromFiniteEnum' instead.+gtoEnum' :: forall opts a. (Generic a, GEnum opts (Rep a)) => String -> Int -> a+gtoEnum' name n+  | 0 <= n && n < card = gtoEnumRaw' @opts n+  | otherwise = error $+      name ++ ": out of bounds, index " ++ show n ++ ", cardinality " ++ show card+  where+    card = gCardinality @opts @(Rep a)++-- | Generic 'fromEnum'. Use 'gfromEnum' or 'gfromFiniteEnum' instead.+gfromEnum' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> Int+gfromEnum' = gFromEnum @opts . from++-- | > genumMin == gfromEnum gminBound+genumMin :: Int+genumMin = 0++-- | > genumMin == gfromEnum gmaxBound+genumMax :: forall opts a. (Generic a, GEnum opts (Rep a)) => Int+genumMax = gCardinality @opts @(Rep a) - 1++-- | Generic 'enumFrom'. Use 'genumFrom' or 'gfiniteEnumFrom' instead.+genumFrom' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> [a]+genumFrom' x = map toE [ i_x .. genumMax @opts @a ]+  where+    toE = gtoEnumRaw' @opts+    i_x = gfromEnum'  @opts x++-- | Generic 'enumFromThen'. Use 'genumFromThen' or 'gfiniteEnumFromThen' instead.+genumFromThen' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> a -> [a]+genumFromThen' x1 x2 = map toE [ i_x1, i_x2 .. bound ]+  where+    toE  = gtoEnumRaw' @opts+    i_x1 = gfromEnum'  @opts x1+    i_x2 = gfromEnum'  @opts x2+    bound | i_x1 >= i_x2 = genumMin+          | otherwise    = genumMax @opts @a++-- | Generic 'enumFromTo'. Use 'genumFromTo' or 'gfiniteEnumFromTo' instead.+genumFromTo' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> a -> [a]+genumFromTo' x y = map toE [ i_x .. i_y ]+  where+    toE = gtoEnumRaw' @opts+    i_x = gfromEnum'  @opts x+    i_y = gfromEnum'  @opts y++-- | Generic 'enumFromThenTo'. Use 'genumFromThenTo' or 'gfiniteEnumFromThenTo' instead.+genumFromThenTo' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> a -> a -> [a]+genumFromThenTo' x1 x2 y = map toE [ i_x1, i_x2 .. i_y ]+  where+    toE  = gtoEnumRaw' @opts+    i_x1 = gfromEnum'  @opts x1+    i_x2 = gfromEnum'  @opts x2+    i_y  = gfromEnum'  @opts y+ -- | Generic 'minBound'. -- -- @@@ -48,32 +178,95 @@ gmaxBound = to gMaxBound  -- | Generic representation of 'Enum' types.-class GEnum f where-  gCardinality :: proxy f -> Int+--+-- The @opts@ parameter is a type-level option to select different+-- implementations.+class GEnum opts f where+  gCardinality :: Int   gFromEnum :: f p -> Int   gToEnum :: Int -> f p -instance GEnum f => GEnum (M1 i c f) where-  gCardinality _ = gCardinality (Proxy :: Proxy f)-  gFromEnum = gFromEnum . unM1-  gToEnum = M1 . gToEnum+-- | Standard option for 'GEnum': derive 'Enum' for types with only nullary+-- constructors (the same restrictions as in the [Haskell 2010+-- report](https://www.haskell.org/onlinereport/haskell2010/haskellch11.html#x18-18400011.2)).+data StandardEnum -instance (GEnum f, GEnum g) => GEnum (f :+: g) where-  gCardinality _ = gCardinality (Proxy :: Proxy f) + gCardinality (Proxy :: Proxy g)-  gFromEnum (L1 x) = gFromEnum x-  gFromEnum (R1 y) = cardF + gFromEnum y+-- | Extends the 'StandardEnum' option for 'GEnum' to allow all constructors to +-- have arbitrary many fields. Each field type must be an instance of +-- both 'Enum' and 'Bounded'. Two restrictions require the user's caution:+--+-- * The 'Enum' instances of the field types need to start enumerating from 0. +-- Particularly 'Int' is an unfit field type, because the enumeration of the +-- negative values starts before 0. +--+-- * Since 'GEnum' represents the cardinality explicitly as an 'Int', there can+-- only be up to 'maxBound' values. This restriction makes 'Word' an invalid field+-- type. Notably it is insufficient for each individual field types to stay+-- below this limit. Instead it applies to the generic type as a whole.+-- +-- The resulting 'GEnum' instance starts enumerating from @0@ up to +-- @(cardinality - 1)@ and respects the generic 'Ord' instance. +-- Implied by this the values from different constructors are enumerated+-- sequentially. They are not interleaved. +--+-- To be very exact: The aforementioned generic 'Ord' instance can be determined+-- by constraining the field types to 'Enum' instead of 'Ord'. Each field's +-- order on its values is given by their enumeration.+-- +-- > data Example = C0 Bool Bool | C1 Bool+-- >   deriving (Eq, Ord, Show, Generic)+-- >+-- > gCardinality == 6  -- 2 * 2 + 2+-- > +-- > enumeration = +-- >     [ C0 False False+-- >     , C0 False  True+-- >     , C0  True False+-- >     , C0  True  True+-- >     , C1 False+-- >     , C1 True+-- >     ]+-- >+-- > enumeration == map gtoFiniteEnum [0 .. 5]+-- > [0 .. 5] == map gfromFiniteEnum enumeration+data FiniteEnum++instance GEnum opts f => GEnum opts (M1 i c f) where+  gCardinality = gCardinality @opts @f+  gFromEnum = gFromEnum @opts . unM1+  gToEnum = M1 . gToEnum @opts++instance (GEnum opts f, GEnum opts g) => GEnum opts (f :+: g) where+  gCardinality = gCardinality @opts @f + gCardinality @opts @g+  gFromEnum (L1 x) = gFromEnum @opts x+  gFromEnum (R1 y) = cardF + gFromEnum @opts y     where-      cardF = gCardinality (Proxy :: Proxy f)+      cardF = gCardinality @opts @f   gToEnum n-    | n < cardF = L1 (gToEnum n)-    | otherwise = R1 (gToEnum (n - cardF))+    | n < cardF = L1 (gToEnum @opts n)+    | otherwise = R1 (gToEnum @opts (n - cardF))     where-      cardF = gCardinality (Proxy :: Proxy f)+      cardF = gCardinality @opts @f -instance GEnum U1 where-  gCardinality _ = 1+instance (GEnum FiniteEnum f, GEnum FiniteEnum g) => GEnum FiniteEnum (f :*: g) where+  gCardinality = gCardinality @FiniteEnum @f * gCardinality @FiniteEnum @g+  gFromEnum (x :*: y) = gFromEnum @FiniteEnum x * cardG + gFromEnum @FiniteEnum y+    where+      cardG = gCardinality @FiniteEnum @g+  gToEnum n = gToEnum @FiniteEnum x :*: gToEnum @FiniteEnum y+    where+      (x, y) = n `quotRem` cardG+      cardG = gCardinality @FiniteEnum @g+  +instance GEnum opts U1 where+  gCardinality = 1   gFromEnum U1 = 0   gToEnum _ = U1++instance (Bounded c, Enum c) => GEnum FiniteEnum (K1 i c) where+  gCardinality = fromEnum (maxBound :: c) + 1+  gFromEnum = fromEnum . unK1+  gToEnum = K1 . toEnum  -- | Generic representation of 'Bounded' types. class GBounded f where
src/Generic/Data/Internal/Generically.hs view
@@ -40,13 +40,33 @@   mempty = gmempty   mappend = gmappend' -instance (Generic a, GEnum (Rep a)) => Enum (Generically a) where-  fromEnum = gfromEnum+instance (Generic a, GEnum StandardEnum (Rep a)) => Enum (Generically a) where   toEnum = gtoEnum+  fromEnum = gfromEnum+  enumFrom = genumFrom+  enumFromThen = genumFromThen+  enumFromTo = genumFromTo+  enumFromThenTo = genumFromThenTo  instance (Generic a, GBounded (Rep a)) => Bounded (Generically a) where   minBound = gminBound   maxBound = gmaxBound++-- | Type with 'Enum' instance derived via 'Generic' with 'FiniteEnum' option.+newtype FiniteEnumeration a = FiniteEnumeration { unFiniteEnumeration :: a }++instance Generic a => Generic (FiniteEnumeration a) where+  type Rep (FiniteEnumeration a) = Rep a+  to = FiniteEnumeration . to+  from = from . unFiniteEnumeration++instance (Generic a, GEnum FiniteEnum (Rep a)) => Enum (FiniteEnumeration a) where+  toEnum = gtoFiniteEnum+  fromEnum = gfromFiniteEnum+  enumFrom = gfiniteEnumFrom+  enumFromThen = gfiniteEnumFromThen+  enumFromTo = gfiniteEnumFromTo+  enumFromThenTo = gfiniteEnumFromThenTo  -- | Type with instances derived via 'Generic1'. newtype Generically1 f a = Generically1 { unGenerically1 :: f a }
test/unit.hs view
@@ -40,9 +40,27 @@ pl1 :: PTy1 [Int] pl1 = p1 -data E = E0 | E1 | E2+data E = E0 | E1 | E2 | E3   deriving (Eq, Show, Generic) +data FiniteE = SE0 Bool Bool | SE1 Bool+  deriving (Eq, Ord, Show, Generic)++e0, e1, eLast :: FiniteE+e0 = allEs !! 0+e1 = allEs !! 1+eLast = last allEs++allEs :: [FiniteE]+allEs = +    [ SE0 False False+    , SE0 False  True+    , SE0  True False+    , SE0  True  True+    , SE1 False+    , SE1 True+    ]+ maybeModuleName :: String #if MIN_VERSION_base(4,12,0) maybeModuleName = "GHC.Maybe"@@ -93,13 +111,23 @@       ]   , testGroup "Bounded"       [ testCase "minBound @E" $ E0 @?= gminBound-      , testCase "maxBound @E" $ E2 @?= gmaxBound+      , testCase "maxBound @E" $ E3 @?= gmaxBound       , testCase "minBound @(P Int)" $ p' minBound minBound @?= gminBound       , testCase "maxBound @(P Int)" $ p' maxBound maxBound @?= gmaxBound       ]   , testGroup "Enum"-      [ testCase "toEnum" $ [E0, E1, E2] @?= fmap gtoEnum [0, 1, 2]-      , testCase "fromEnum" $ [0, 1, 2] @?= fmap gfromEnum [E0, E1, E2]+      [ testCase "toEnum" $ [E0, E1, E2, E3] @?= fmap gtoEnum [0, 1, 2, 3]+      , testCase "fromEnum" $ [0, 1, 2, 3] @?= fmap gfromEnum [E0, E1, E2, E3]+      , testCase "enumFrom" $ [E0, E1, E2, E3] @?= genumFrom E0+      , testCase "enumFromThen" $ [E0, E1, E2, E3] @?= genumFromThen E0 E1+      , testCase "enumFromTo" $ [E0, E1, E2, E3] @?= genumFromTo E0 E3+      , testCase "enumFromThenTo" $ [E0, E1, E2, E3] @?= genumFromThenTo E0 E1 E3+      , testCase "toEnum (FiniteEnum)" $ allEs @?= fmap gtoFiniteEnum [0 .. 5]+      , testCase "fromEnum (FiniteEnum)" $ [0 .. 5] @?= fmap gfromFiniteEnum allEs+      , testCase "enumFrom (FiniteEnum)" $ allEs @?= gfiniteEnumFrom e0+      , testCase "enumFromThen (FiniteEnum)" $ allEs @?= gfiniteEnumFromThen e0 e1+      , testCase "enumFromTo (FiniteEnum)" $ allEs @?= gfiniteEnumFromTo e0 eLast+      , testCase "enumFromThenTo (FiniteEnum)" $ allEs @?= gfiniteEnumFromThenTo e0 e1 eLast       ]   , testGroup "Show"       [ testCase "show" $ "P 1 2" @?= show (p' 1 2)