1
- module Data.Enum where
1
+ module Data.Enum
2
+ ( Enum
3
+ , Cardinality (..)
4
+ , fromEnum
5
+ , runCardinality
6
+ , toEnum
7
+ ) where
2
8
3
- import Data.Maybe
9
+ import Data.Maybe
10
+ import Data.Tuple
11
+ import Data.Maybe.Unsafe
4
12
5
- class Enum a where
6
- toEnum :: Number -> Maybe a
7
- fromEnum :: a -> Number
13
+ newtype Cardinality a = Cardinality Number
8
14
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
11
17
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