module Data.Enumerable.Generic (
allEnum
, allConstEnum
, allDefsEnum
, Enumerable(..)
, Defaults(..)
, Default(..)
) where
import GHC.Generics
import Data.Default (Default, def)
import Control.Arrow (first, second)
import Data.Word (Word, Word8, Word16, Word32, Word64)
import Data.Int (Int8, Int16, Int32, Int64)
allEnum :: (Default x, Enumerable x) => [x]
allEnum = allNext def
allConstEnum :: (Enumerable x) => [x] -> [x]
allConstEnum = concatMap allNext
allDefsEnum :: (Defaults x, Enumerable x) => [x]
allDefsEnum = allConstEnum defs
class GEnumerable x where
gper :: x a -> (x a, Bool)
class Defaults x where
defs :: [x]
class Enumerable x where
per :: x -> (x, Bool)
default per :: (Generic x, GEnumerable (Rep x)) => x -> (x, Bool)
per = first to . gper . from
sper :: (x, Bool) -> (x, Bool)
sper (x, False) = (x, False)
sper (x, True) = per x
next :: x -> x
next = fst . per
allNext :: x -> [x]
allNext x = map fst . takeWhile (not . snd) $ iterate (sper . second (const True)) (x, False)
defEnumerable :: (Eq x, Enum x, Bounded x) => x -> (x, Bool)
defEnumerable x = if maxBound == x then (minBound, True) else (succ x, False)
instance Default Bool where def = False
instance Default Char where def = '\0'
instance (Default a, Default b) => Default (Either a b) where
def = Left def
instance Enumerable Bool where per = defEnumerable
instance Enumerable Char where per = defEnumerable
instance Enumerable Int where per = defEnumerable
instance Enumerable Int8 where per = defEnumerable
instance Enumerable Int16 where per = defEnumerable
instance Enumerable Int32 where per = defEnumerable
instance Enumerable Int64 where per = defEnumerable
instance Enumerable Ordering where per = defEnumerable
instance Enumerable Word where per = defEnumerable
instance Enumerable Word8 where per = defEnumerable
instance Enumerable Word16 where per = defEnumerable
instance Enumerable Word32 where per = defEnumerable
instance Enumerable Word64 where per = defEnumerable
instance Enumerable () where per = defEnumerable
instance (Default a, Default b, Enumerable a, Enumerable b) => Enumerable (Either a b) where
per (Left a) = (if carry then Right def else Left nexta, False)
where (nexta, carry) = per a
per (Right b) = (if carry then Left def else Right nextb, carry)
where (nextb, carry) = per b
instance (Default x, Enumerable x) => Enumerable (Maybe x) where
per Nothing = (Just def, False)
per (Just a) = (if carry then Nothing else Just nexta, carry)
where (nexta, carry) = per a
instance (Enumerable a, Enumerable b) => Enumerable (a, b) where
per (a, b) = if carrya then ((a', b'), carryb) else ((a', b), False)
where (a', carrya) = per a
(b', carryb) = per b
instance (GEnumerable x, GEnumerable y) => GEnumerable (x :*: y) where
gper (x :*: y) = if carry then first (ntype :*:) $ gper y
else (ntype :*: y, False)
where (ntype, carry) = gper x
instance (GEnumerable x, GEnumerable y) => GEnumerable (x :+: y) where
gper (L1 x) = first L1 $ gper x
gper (R1 x) = first R1 $ gper x
instance (GEnumerable x) => GEnumerable (M1 i c x) where
gper (M1 x) = first M1 $ gper x
instance (Enumerable x) => GEnumerable (K1 i x) where
gper (K1 x) = first K1 $ per x
instance GEnumerable (U1) where
gper U1 = (U1, True)