Skip to content

Commit

Permalink
Merge pull request #1 from jdegoes/ready/sane-enums
Browse files Browse the repository at this point in the history
change structure & add laws for enums
  • Loading branch information
garyb committed Oct 12, 2014
2 parents 28e2a45 + 0af1c67 commit 958f7fb
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 15 deletions.
30 changes: 25 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
toEnum :: forall a. (Enum a) => Number -> Maybe a
3 changes: 2 additions & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"package.json"
],
"dependencies": {
"purescript-maybe": "*"
"purescript-maybe": "*",
"purescript-tuples": "*"
}
}
96 changes: 87 additions & 9 deletions src/Data/Enum.purs
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)

0 comments on commit 958f7fb

Please sign in to comment.