1- module Data.Enum where
1+ module Data.Enum
2+ ( Enum
3+ , Cardinality (..)
4+ , fromEnum
5+ , runCardinality
6+ , toEnum
7+ ) where
28
3- import Data.Maybe
9+ import Data.Maybe
10+ import Data.Tuple
11+ import Data.Maybe.Unsafe
412
5- class Enum a where
6- toEnum :: Number -> Maybe a
7- fromEnum :: a -> Number
13+ newtype Cardinality a = Cardinality Number
814
9- succ :: forall a . ( Enum a ) => a -> Maybe a
10- succ x = toEnum (fromEnum x + 1 )
15+ run Cardinality :: forall a. Cardinality a -> Number
16+ run Cardinality ( Cardinality a ) = a
1117
12- pred :: forall a . (Enum a ) => a -> Maybe a
13- pred x = toEnum (fromEnum x - 1 )
18+ -- | Type class for enumerations. This should not be considered a part of a
19+ -- | numeric hierarchy, ala Haskell. Rather, this is a type class for small,
20+ -- | ordered sum types with statically-determined cardinality and the ability
21+ -- | to easily compute successor and predecessor elements. e.g. DayOfWeek, etc.
22+ -- |
23+ -- | Laws:
24+ -- | succ firstEnum >>= succ >>= succ ... succ [cardinality times] == lastEnum
25+ -- | pred lastEnum >>= pred >>= pred ... pred [cardinality times] == firstEnum
26+ -- |
27+ -- | Just $ e1 `compare` e2 == fromEnum e1 `compare` fromEnum e2
28+ -- |
29+ -- | for all a > firstEnum: pred a >>= succ == Just a
30+ -- | for all a < lastEnum: succ a >>= pred == Just a
31+ class (Ord a ) <= Enum a where
32+ cardinality :: Cardinality a
33+
34+ firstEnum :: a
35+
36+ lastEnum :: a
37+
38+ succ :: a -> Maybe a
39+
40+ pred :: a -> Maybe a
41+
42+ toEnum :: forall a. (Enum a ) => Number -> Maybe a
43+ toEnum n | n < 0 = Nothing
44+ toEnum 0 = Just firstEnum
45+ toEnum n = toEnum (n - 1) >>= succ
46+
47+ fromEnum :: forall a. (Enum a ) => a -> Number
48+ fromEnum e = maybe 0 ((+) 1 <<< fromEnum ) (pred e )
49+
50+ maybeCardinality :: forall a. (Enum a ) => Cardinality a -> Cardinality (Maybe a )
51+ maybeCardinality c = Cardinality $ 1 + (runCardinality c )
52+
53+ instance enumMaybe :: (Enum a ) => Enum (Maybe a ) where
54+ cardinality = maybeCardinality cardinality
55+
56+ firstEnum = Nothing
57+
58+ lastEnum = Just $ lastEnum
59+
60+ succ Nothing = Just $ firstEnum
61+ succ (Just a ) = Just <$> succ a
62+
63+ pred Nothing = Nothing
64+ pred (Just a ) = Just <$> pred a
65+
66+ instance enumBoolean :: Enum Boolean where
67+ cardinality = Cardinality 2
68+
69+ firstEnum = false
70+
71+ lastEnum = true
72+
73+ succ false = Just true
74+ succ _ = Nothing
75+
76+ pred true = Just false
77+ pred _ = Nothing
78+
79+ instance enumTuple :: (Enum a , Enum b ) => Enum (Tuple a b ) where
80+ cardinality = tupleCardinality cardinality cardinality
81+
82+ firstEnum = Tuple firstEnum firstEnum
83+
84+ lastEnum = Tuple lastEnum lastEnum
85+
86+ succ (Tuple a b ) = maybe (flip Tuple firstEnum <$> succ a ) (Just <<< Tuple a ) (succ b )
87+
88+ pred (Tuple a b ) = maybe (flip Tuple firstEnum <$> pred a ) (Just <<< Tuple a ) (pred b )
89+
90+ tupleCardinality :: forall a b. (Enum a , Enum b ) => Cardinality a -> Cardinality b -> Cardinality (Tuple a b )
91+ tupleCardinality l r = Cardinality $ (runCardinality l ) * (runCardinality r )
0 commit comments