Skip to content

change structure & add laws for enums #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 12, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)