diff --git a/README.md b/README.md index e133986..5ca8ea2 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,35 @@ ## Module Data.Enum +### Types + + newtype Cardinality a where + Cardinality :: Number -> Cardinality a + + ### Type Classes - class Enum a where - toEnum :: Prim.Number -> Maybe a - fromEnum :: a -> Prim.Number + class (Ord a) <= Enum a where + cardinality :: Cardinality a + firstEnum :: a + lastEnum :: a + succ :: a -> Maybe a + pred :: a -> Maybe a + + +### Type Class Instances + + instance enumBoolean :: Enum Boolean + + instance enumMaybe :: (Enum a) => Enum (Maybe a) + + instance enumTuple :: (Enum a, Enum b) => Enum (Tuple a b) ### Values - pred :: forall a. (Enum a) => a -> Maybe a + fromEnum :: forall a. (Enum a) => a -> Number + + runCardinality :: forall a. Cardinality a -> Number - succ :: forall a. (Enum a) => a -> Maybe a \ No newline at end of file + toEnum :: forall a. (Enum a) => Number -> Maybe a \ No newline at end of file diff --git a/bower.json b/bower.json index ab239dc..0345a4c 100644 --- a/bower.json +++ b/bower.json @@ -18,6 +18,7 @@ "package.json" ], "dependencies": { - "purescript-maybe": "*" + "purescript-maybe": "*", + "purescript-tuples": "*" } } diff --git a/src/Data/Enum.purs b/src/Data/Enum.purs index acb2961..8c77592 100644 --- a/src/Data/Enum.purs +++ b/src/Data/Enum.purs @@ -1,13 +1,91 @@ -module Data.Enum where +module Data.Enum + ( Enum + , Cardinality(..) + , fromEnum + , runCardinality + , toEnum + ) where -import Data.Maybe + import Data.Maybe + import Data.Tuple + import Data.Maybe.Unsafe -class Enum a where - toEnum :: Number -> Maybe a - fromEnum :: a -> Number + newtype Cardinality a = Cardinality Number -succ :: forall a. (Enum a) => a -> Maybe a -succ x = toEnum (fromEnum x + 1) + runCardinality :: forall a. Cardinality a -> Number + runCardinality (Cardinality a) = a -pred :: forall a. (Enum a) => a -> Maybe a -pred x = toEnum (fromEnum x - 1) \ No newline at end of file + -- | Type class for enumerations. This should not be considered a part of a + -- | numeric hierarchy, ala Haskell. Rather, this is a type class for small, + -- | ordered sum types with statically-determined cardinality and the ability + -- | to easily compute successor and predecessor elements. e.g. DayOfWeek, etc. + -- | + -- | Laws: + -- | succ firstEnum >>= succ >>= succ ... succ [cardinality times] == lastEnum + -- | pred lastEnum >>= pred >>= pred ... pred [cardinality times] == firstEnum + -- | + -- | Just $ e1 `compare` e2 == fromEnum e1 `compare` fromEnum e2 + -- | + -- | for all a > firstEnum: pred a >>= succ == Just a + -- | for all a < lastEnum: succ a >>= pred == Just a + class (Ord a) <= Enum a where + cardinality :: Cardinality a + + firstEnum :: a + + lastEnum :: a + + succ :: a -> Maybe a + + pred :: a -> Maybe a + + toEnum :: forall a. (Enum a) => Number -> Maybe a + toEnum n | n < 0 = Nothing + toEnum 0 = Just firstEnum + toEnum n = toEnum (n - 1) >>= succ + + fromEnum :: forall a. (Enum a) => a -> Number + fromEnum e = maybe 0 ((+) 1 <<< fromEnum) (pred e) + + maybeCardinality :: forall a. (Enum a) => Cardinality a -> Cardinality (Maybe a) + maybeCardinality c = Cardinality $ 1 + (runCardinality c) + + instance enumMaybe :: (Enum a) => Enum (Maybe a) where + cardinality = maybeCardinality cardinality + + firstEnum = Nothing + + lastEnum = Just $ lastEnum + + succ Nothing = Just $ firstEnum + succ (Just a) = Just <$> succ a + + pred Nothing = Nothing + pred (Just a) = Just <$> pred a + + instance enumBoolean :: Enum Boolean where + cardinality = Cardinality 2 + + firstEnum = false + + lastEnum = true + + succ false = Just true + succ _ = Nothing + + pred true = Just false + pred _ = Nothing + + instance enumTuple :: (Enum a, Enum b) => Enum (Tuple a b) where + cardinality = tupleCardinality cardinality cardinality + + firstEnum = Tuple firstEnum firstEnum + + lastEnum = Tuple lastEnum lastEnum + + succ (Tuple a b) = maybe (flip Tuple firstEnum <$> succ a) (Just <<< Tuple a) (succ b) + + pred (Tuple a b) = maybe (flip Tuple firstEnum <$> pred a) (Just <<< Tuple a) (pred b) + + tupleCardinality :: forall a b. (Enum a, Enum b) => Cardinality a -> Cardinality b -> Cardinality (Tuple a b) + tupleCardinality l r = Cardinality $ (runCardinality l) * (runCardinality r) \ No newline at end of file