-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from jdegoes/ready/sane-enums
change structure & add laws for enums
- Loading branch information
Showing
3 changed files
with
114 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
-- | 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) |