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 +8/−0
- generic-data.cabal +1/−1
- src/Generic/Data.hs +17/−2
- src/Generic/Data/Internal/Data.hs +4/−3
- src/Generic/Data/Internal/Enum.hs +221/−28
- src/Generic/Data/Internal/Generically.hs +22/−2
- test/unit.hs +32/−4
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)