|
| 1 | +module Data.Generic.Rep.Enum where |
| 2 | + |
| 3 | +import Prelude |
| 4 | + |
| 5 | +import Data.Enum (class BoundedEnum, class Enum, Cardinality(..), cardinality, fromEnum, pred, succ, toEnum) |
| 6 | +import Data.Generic.Rep (class Generic, Argument(..), Constructor(..), NoArguments(..), Sum(..), from, to) |
| 7 | +import Data.Generic.Rep.Bounded (class GenericBottom, class GenericTop, genericBottom', genericTop') |
| 8 | +import Data.Maybe (Maybe(..)) |
| 9 | +import Data.Newtype (unwrap) |
| 10 | + |
| 11 | +class GenericEnum a where |
| 12 | + genericPred' :: a -> Maybe a |
| 13 | + genericSucc' :: a -> Maybe a |
| 14 | + |
| 15 | +instance genericEnumNoArguments :: GenericEnum NoArguments where |
| 16 | + genericPred' _ = Nothing |
| 17 | + genericSucc' _ = Nothing |
| 18 | + |
| 19 | +instance genericEnumArgument :: Enum a => GenericEnum (Argument a) where |
| 20 | + genericPred' (Argument a) = Argument <$> pred a |
| 21 | + genericSucc' (Argument a) = Argument <$> succ a |
| 22 | + |
| 23 | +instance genericEnumConstructor :: GenericEnum a => GenericEnum (Constructor name a) where |
| 24 | + genericPred' (Constructor a) = Constructor <$> genericPred' a |
| 25 | + genericSucc' (Constructor a) = Constructor <$> genericSucc' a |
| 26 | + |
| 27 | +instance genericEnumSum :: (GenericEnum a, GenericTop a, GenericEnum b, GenericBottom b) => GenericEnum (Sum a b) where |
| 28 | + genericPred' = case _ of |
| 29 | + Inl a -> Inl <$> genericPred' a |
| 30 | + Inr b -> case genericPred' b of |
| 31 | + Nothing -> Just (Inl genericTop') |
| 32 | + Just b' -> Just (Inr b') |
| 33 | + genericSucc' = case _ of |
| 34 | + Inl a -> case genericSucc' a of |
| 35 | + Nothing -> Just (Inr genericBottom') |
| 36 | + Just a' -> Just (Inl a') |
| 37 | + Inr b -> Inr <$> genericSucc' b |
| 38 | + |
| 39 | +-- | A `Generic` implementation of the `pred` member from the `Enum` type class. |
| 40 | +genericPred :: forall a rep. Generic a rep => GenericEnum rep => a -> Maybe a |
| 41 | +genericPred = map to <<< genericPred' <<< from |
| 42 | + |
| 43 | +-- | A `Generic` implementation of the `succ` member from the `Enum` type class. |
| 44 | +genericSucc :: forall a rep. Generic a rep => GenericEnum rep => a -> Maybe a |
| 45 | +genericSucc = map to <<< genericSucc' <<< from |
| 46 | + |
| 47 | +class GenericBoundedEnum a where |
| 48 | + genericCardinality' :: Cardinality a |
| 49 | + genericToEnum' :: Int -> Maybe a |
| 50 | + genericFromEnum' :: a -> Int |
| 51 | + |
| 52 | +instance genericBoundedEnumNoArguments :: GenericBoundedEnum NoArguments where |
| 53 | + genericCardinality' = Cardinality 1 |
| 54 | + genericToEnum' i = if i == 0 then Just NoArguments else Nothing |
| 55 | + genericFromEnum' _ = 0 |
| 56 | + |
| 57 | +instance genericBoundedEnumArgument :: BoundedEnum a => GenericBoundedEnum (Argument a) where |
| 58 | + genericCardinality' = Cardinality (unwrap (cardinality :: Cardinality a)) |
| 59 | + genericToEnum' i = Argument <$> toEnum i |
| 60 | + genericFromEnum' (Argument a) = fromEnum a |
| 61 | + |
| 62 | +instance genericBoundedEnumConstructor :: GenericBoundedEnum a => GenericBoundedEnum (Constructor name a) where |
| 63 | + genericCardinality' = Cardinality (unwrap (genericCardinality' :: Cardinality a)) |
| 64 | + genericToEnum' i = Constructor <$> genericToEnum' i |
| 65 | + genericFromEnum' (Constructor a) = genericFromEnum' a |
| 66 | + |
| 67 | +instance genericBoundedEnumSum :: (GenericBoundedEnum a, GenericBoundedEnum b) => GenericBoundedEnum (Sum a b) where |
| 68 | + genericCardinality' = |
| 69 | + Cardinality |
| 70 | + $ unwrap (genericCardinality' :: Cardinality a) |
| 71 | + + unwrap (genericCardinality' :: Cardinality b) |
| 72 | + genericToEnum' n = to genericCardinality' |
| 73 | + where |
| 74 | + to :: Cardinality a -> Maybe (Sum a b) |
| 75 | + to (Cardinality ca) |
| 76 | + | n >= 0 && n < ca = Inl <$> genericToEnum' n |
| 77 | + | otherwise = Inr <$> genericToEnum' (n - ca) |
| 78 | + genericFromEnum' = case _ of |
| 79 | + Inl a -> genericFromEnum' a |
| 80 | + Inr b -> genericFromEnum' b + unwrap (genericCardinality' :: Cardinality a) |
| 81 | + |
| 82 | +-- | A `Generic` implementation of the `cardinality` member from the |
| 83 | +-- | `BoundedEnum` type class. |
| 84 | +genericCardinality :: forall a rep. Generic a rep => GenericBoundedEnum rep => Cardinality a |
| 85 | +genericCardinality = Cardinality (unwrap (genericCardinality' :: Cardinality rep)) |
| 86 | + |
| 87 | +-- | A `Generic` implementation of the `toEnum` member from the `BoundedEnum` |
| 88 | +-- | type class. |
| 89 | +genericToEnum :: forall a rep. Generic a rep => GenericBoundedEnum rep => Int -> Maybe a |
| 90 | +genericToEnum = map to <<< genericToEnum' |
| 91 | + |
| 92 | +-- | A `Generic` implementation of the `fromEnum` member from the `BoundedEnum` |
| 93 | +-- | type class. |
| 94 | +genericFromEnum :: forall a rep. Generic a rep => GenericBoundedEnum rep => a -> Int |
| 95 | +genericFromEnum = genericFromEnum' <<< from |
0 commit comments