diff --git a/.gitignore b/.gitignore index e2f8a69..307f9c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ -.psci +/.* +!/.gitignore +!/.travis.yml /bower_components/ /node_modules/ /output/ -/tmp/ diff --git a/.travis.yml b/.travis.yml index 791313a..36183ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: node_js -sudo: false -node_js: - - 0.10 +sudo: required +dist: trusty +node_js: 5 env: - PATH=$HOME/purescript:$PATH install: @@ -9,6 +9,16 @@ install: - wget -O $HOME/purescript.tar.gz https://github.com/purescript/purescript/releases/download/$TAG/linux64.tar.gz - tar -xvf $HOME/purescript.tar.gz -C $HOME/ - chmod a+x $HOME/purescript + - npm install -g bower - npm install + - bower install script: - npm run build +after_success: +- >- + test $TRAVIS_TAG && + psc-publish > .pursuit.json && + curl -X POST http://pursuit.purescript.org/packages \ + -d @.pursuit.json \ + -H 'Accept: application/json' \ + -H "Authorization: token ${GITHUB_TOKEN}" diff --git a/README.md b/README.md index 50d438e..329185a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Build Status](https://travis-ci.org/purescript/purescript-enums.svg?branch=master)](https://travis-ci.org/purescript/purescript-enums) [![Dependency Status](https://www.versioneye.com/user/projects/55848c63363861001d000330/badge.svg?style=flat)](https://www.versioneye.com/user/projects/55848c63363861001d000330) -Operations for small ordered sum types. +Operations for sequentially ordered types. ## Installation @@ -12,6 +12,6 @@ Operations for small ordered sum types. bower install purescript-enums ``` -## Module documentation +## Documentation -- [Data.Enum](docs/Data/Enum.md) +Module documentation is [published on Pursuit](http://pursuit.purescript.org/packages/purescript-enums). diff --git a/bower.json b/bower.json index 6b5567e..6fda6c7 100644 --- a/bower.json +++ b/bower.json @@ -2,9 +2,6 @@ "name": "purescript-enums", "homepage": "https://github.com/purescript/purescript-enums", "description": "Operations for sequentially ordered types", - "keywords": [ - "purescript" - ], "license": "MIT", "repository": { "type": "git", @@ -21,8 +18,8 @@ "package.json" ], "dependencies": { - "purescript-either": "^0.2.0", - "purescript-strings": "^0.7.0", - "purescript-unfoldable": "^0.4.0" + "purescript-either": "^1.0.0-rc.1", + "purescript-strings": "^1.0.0-rc.1", + "purescript-unfoldable": "^1.0.0-rc.1" } } diff --git a/docs/Data/Enum.md b/docs/Data/Enum.md deleted file mode 100644 index cec3add..0000000 --- a/docs/Data/Enum.md +++ /dev/null @@ -1,151 +0,0 @@ -## Module Data.Enum - -#### `Cardinality` - -``` purescript -newtype Cardinality a - = Cardinality Int -``` - -#### `runCardinality` - -``` purescript -runCardinality :: forall a. Cardinality a -> Int -``` - -#### `Enum` - -``` purescript -class Enum a where - succ :: a -> Maybe a - pred :: a -> Maybe a - toEnum :: Int -> Maybe a - fromEnum :: a -> Int -``` - -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 the ability to easily compute successor and -predecessor elements. e.g. `DayOfWeek`, etc. - -Laws: - -- ```e1 `compare` e2 == fromEnum e1 `compare` fromEnum e2``` -- ```pred >=> succ >=> pred = pred``` -- ```succ >=> pred >=> succ = succ``` -- ```toEnum (fromEnum a) = Just a``` - -##### Instances -``` purescript -instance enumUnit :: Enum Unit -instance enumChar :: Enum Char -instance enumMaybe :: (Finite a) => Enum (Maybe a) -instance enumBoolean :: Enum Boolean -instance enumTuple :: (Finite a, Finite b) => Enum (Tuple a b) -instance enumEither :: (Finite a, Finite b) => Enum (Either a b) -``` - -#### `defaultSucc` - -``` purescript -defaultSucc :: forall a. (Int -> Maybe a) -> (a -> Int) -> a -> Maybe a -``` - -```defaultSucc toEnum fromEnum = succ``` - -#### `defaultPred` - -``` purescript -defaultPred :: forall a. (Int -> Maybe a) -> (a -> Int) -> a -> Maybe a -``` - -```defaultPred toEnum fromEnum = pred``` - -#### `defaultToEnum` - -``` purescript -defaultToEnum :: forall a. (a -> Maybe a) -> a -> Int -> Maybe a -``` - -Runs in `O(n)` where `n` is `fromEnum a` - -```defaultToEnum succ bottom = toEnum``` - -#### `defaultFromEnum` - -``` purescript -defaultFromEnum :: forall a. (a -> Maybe a) -> a -> Int -``` - -Runs in `O(n)` where `n` is `fromEnum a` - -```defaultFromEnum pred = fromEnum``` - -#### `enumFromTo` - -``` purescript -enumFromTo :: forall a. (Enum a) => a -> a -> Array a -``` - -Property: ```fromEnum a = a', fromEnum b = b' => forall e', a' <= e' <= b': Exists e: toEnum e' = Just e``` - -Following from the propery of `intFromTo`, we are sure all elements in `intFromTo (fromEnum a) (fromEnum b)` are `Just`s. - -#### `enumFromThenTo` - -``` purescript -enumFromThenTo :: forall a. (Enum a) => a -> a -> a -> Array a -``` - -`[a,b..c]` - -Correctness for using `fromJust` is the same as for `enumFromTo`. - -#### `intFromTo` - -``` purescript -intFromTo :: Int -> Int -> Array Int -``` - -Property: ```forall e in intFromTo a b: a <= e <= b``` - -#### `intStepFromTo` - -``` purescript -intStepFromTo :: Int -> Int -> Int -> Array Int -``` - -Property: ```forall e in intStepFromTo step a b: a <= e <= b``` - -#### `Finite` - -``` purescript -class (Bounded a, Enum a) <= Finite a where - cardinality :: Cardinality a -``` - -Type class for finite 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 bottom >>= succ >>= succ ... succ [cardinality - 1 times] == top``` -- ```pred top >>= pred >>= pred ... pred [cardinality - 1 times] == bottom``` -- ```forall a > bottom: pred a >>= succ == Just a``` -- ```forall a < top: succ a >>= pred == Just a``` -- ```forall a > bottom: fromEnum <$> pred a = Just (fromEnum a - 1)``` -- ```forall a < top: fromEnum <$> succ a = Just (fromEnum a + 1)``` - -##### Instances -``` purescript -instance finiteUnit :: Finite Unit -instance finiteChar :: Finite Char -instance finiteMaybe :: (Finite a) => Finite (Maybe a) -instance finiteBoolean :: Finite Boolean -instance finiteTuple :: (Finite a, Finite b) => Finite (Tuple a b) -instance finiteEither :: (Finite a, Finite b) => Finite (Either a b) -``` - - diff --git a/package.json b/package.json index 509a91f..f7e0e40 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "private": true, "scripts": { - "postinstall": "pulp dep install", - "build": "pulp build && rimraf docs && pulp docs" + "clean": "rimraf output && rimraf .pulp-cache", + "build": "pulp build" }, "devDependencies": { - "pulp": "^4.0.2", - "rimraf": "^2.4.1" + "pulp": "^8.1.0", + "rimraf": "^2.5.0" } } diff --git a/src/Data/Enum.purs b/src/Data/Enum.purs index 5593275..cf18a30 100644 --- a/src/Data/Enum.purs +++ b/src/Data/Enum.purs @@ -1,58 +1,97 @@ module Data.Enum - ( Enum - , BoundedEnum - , Cardinality(..) - , cardinality - , fromEnum - , pred - , runCardinality - , succ - , toEnum + ( class Enum, succ, pred , defaultSucc , defaultPred - , defaultCardinality - , defaultToEnum - , defaultFromEnum , enumFromTo , enumFromThenTo , upFrom , downFrom + , Cardinality(..), runCardinality + , class BoundedEnum, cardinality, toEnum, fromEnum + , defaultCardinality + , defaultToEnum + , defaultFromEnum ) where import Prelude + import Data.Char (fromCharCode, toCharCode) -import Data.Either -import Data.Maybe -import Data.Maybe.Unsafe -import Data.Tuple -import Data.Unfoldable +import Data.Either (Either(..)) +import Data.Maybe (Maybe(..), maybe, fromJust) +import Data.Tuple (Tuple(..)) +import Data.Unfoldable (class Unfoldable, unfoldr) + +import Partial.Unsafe (unsafePartial) newtype Cardinality a = Cardinality Int runCardinality :: forall a. Cardinality a -> Int runCardinality (Cardinality a) = a --- | 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 the ability to easily compute successor and --- | predecessor elements. e.g. `DayOfWeek`, etc. +-- | Type class for enumerations. -- | -- | Laws: --- | --- | - ```pred >=> succ >=> pred = pred``` --- | - ```succ >=> pred >=> succ = succ``` - -class (Ord a) <= Enum a where +-- | - `succ a > pred a` +-- | - `pred a < succ a` +-- | - `pred >=> succ >=> pred = pred` +-- | - `succ >=> pred >=> succ = succ` +class Ord a <= Enum a where succ :: a -> Maybe a pred :: a -> Maybe a +instance enumBoolean :: Enum Boolean where + succ false = Just true + succ _ = Nothing + pred true = Just false + pred _= Nothing + +instance enumInt :: Enum Int where + succ n = if n < top then Just (n + 1) else Nothing + pred n = if n > bottom then Just (n - 1) else Nothing + +instance enumChar :: Enum Char where + succ = defaultSucc charToEnum toCharCode + pred = defaultPred charToEnum toCharCode + +charToEnum :: Int -> Maybe Char +charToEnum n | n >= bottom && n <= top = Just $ fromCharCode n +charToEnum _ = Nothing + +instance enumUnit :: Enum Unit where + succ = const Nothing + pred = const Nothing + +instance enumOrdering :: Enum Ordering where + succ LT = Just EQ + succ EQ = Just GT + succ GT = Nothing + pred LT = Nothing + pred EQ = Just LT + pred GT = Just EQ + +instance enumMaybe :: BoundedEnum a => Enum (Maybe a) where + succ Nothing = Just $ Just bottom + succ (Just a) = Just <$> succ a + pred Nothing = Nothing + pred (Just a) = Just $ pred a + +instance enumEither :: (BoundedEnum a, BoundedEnum b) => Enum (Either a b) where + succ (Left a) = maybe (Just $ Right bottom) (Just <<< Left) (succ a) + succ (Right b) = maybe (Nothing) (Just <<< Right) (succ b) + pred (Left a) = maybe (Nothing) (Just <<< Left) (pred a) + pred (Right b) = maybe (Just $ Left top) (Just <<< Right) (pred b) + +instance enumTuple :: (Enum a, BoundedEnum b) => Enum (Tuple a b) where + succ (Tuple a b) = maybe (flip Tuple bottom <$> succ a) (Just <<< Tuple a) (succ b) + pred (Tuple a b) = maybe (flip Tuple top <$> pred a) (Just <<< Tuple a) (pred b) + -- | ```defaultSucc toEnum fromEnum = succ``` -defaultSucc :: forall a. (Int -> Maybe a) -> (a -> Int) -> (a -> Maybe a) -defaultSucc toEnum' fromEnum' a = toEnum' (fromEnum' a + one) +defaultSucc :: forall a. (Int -> Maybe a) -> (a -> Int) -> a -> Maybe a +defaultSucc toEnum' fromEnum' a = toEnum' (fromEnum' a + 1) -- | ```defaultPred toEnum fromEnum = pred``` -defaultPred :: forall a. (Int -> Maybe a) -> (a -> Int) -> (a -> Maybe a) -defaultPred toEnum' fromEnum' a = toEnum' (fromEnum' a - one) +defaultPred :: forall a. (Int -> Maybe a) -> (a -> Int) -> a -> Maybe a +defaultPred toEnum' fromEnum' a = toEnum' (fromEnum' a - 1) -- | Property: ```fromEnum a = a', fromEnum b = b' => forall e', a' <= e' <= b': Exists e: toEnum e' = Just e``` -- | @@ -62,13 +101,12 @@ enumFromTo :: forall a u. (Enum a, Unfoldable u) => a -> a -> u a enumFromTo from to = unfoldr (\x -> succ x >>= \x' -> if x <= to then pure $ Tuple x x' else Nothing) from -- | `[a,b..c]` --- | --- | Correctness for using `fromJust` is the same as for `enumFromTo`. -enumFromThenTo :: forall a. (BoundedEnum a) => a -> a -> a -> Array a -enumFromThenTo a b c = (toEnum >>> fromJust) <$> intStepFromTo (b' - a') a' c' - where a' = fromEnum a - b' = fromEnum b - c' = fromEnum c +enumFromThenTo :: forall a. BoundedEnum a => a -> a -> a -> Array a +enumFromThenTo = unsafePartial \a b c -> + let a' = fromEnum a + b' = fromEnum b + c' = fromEnum c + in (toEnum >>> fromJust) <$> intStepFromTo (b' - a') a' c' -- | Property: ```forall e in intStepFromTo step a b: a <= e <= b``` intStepFromTo :: Int -> Int -> Int -> Array Int @@ -79,6 +117,7 @@ intStepFromTo step from to = else Nothing -- End of the collection. ) from +diag :: forall a. a -> Tuple a a diag a = Tuple a a upFrom :: forall a u. (Enum a, Unfoldable u) => a -> u a @@ -87,10 +126,12 @@ upFrom = unfoldr (map diag <<< succ) downFrom :: forall a u. (Enum a, Unfoldable u) => a -> u a downFrom = unfoldr (map diag <<< pred) --- | Type class for finite 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. +-- | Type class for finite enumerations. +-- | +-- | This should not be considered a part of a numeric hierarchy, as in 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`. -- | -- | Laws: -- | @@ -102,39 +143,28 @@ downFrom = unfoldr (map diag <<< pred) -- | - ```forall a < top: fromEnum <$> succ a = Just (fromEnum a + 1)``` -- | - ```e1 `compare` e2 == fromEnum e1 `compare` fromEnum e2``` -- | - ```toEnum (fromEnum a) = Just a``` - class (Bounded a, Enum a) <= BoundedEnum a where cardinality :: Cardinality a toEnum :: Int -> Maybe a fromEnum :: a -> Int --- | Runs in `O(n)` where `n` is `fromEnum top` --- | --- | ```defaultCardinality = cardinality``` -defaultCardinality :: forall a. (Bounded a, Enum a) => Cardinality a -defaultCardinality = Cardinality $ defaultCardinality' one (bottom :: a) where - defaultCardinality' i = maybe i (defaultCardinality' $ i + one) <<< succ - - -- | Runs in `O(n)` where `n` is `fromEnum a` - -- | - -- | ```defaultToEnum succ bottom = toEnum``` --- TODO do we need to pass in bottom? It's a superclass if yes then we should pass it in for defaultCardinality too -defaultToEnum :: forall a. (a -> Maybe a) -> a -> (Int -> Maybe a) -defaultToEnum succ' bottom' n | n < zero = Nothing - | n == zero = Just bottom' - | otherwise = defaultToEnum succ' bottom' (n - one) >>= succ' - - -- | Runs in `O(n)` where `n` is `fromEnum a` - -- | - -- | ```defaultFromEnum pred = fromEnum``` -defaultFromEnum :: forall a. (a -> Maybe a) -> (a -> Int) -defaultFromEnum pred' e = maybe zero (\prd -> defaultFromEnum pred' prd + one) (pred' e) +instance boundedEnumBoolean :: BoundedEnum Boolean where + cardinality = Cardinality 2 + toEnum 0 = Just false + toEnum 1 = Just true + toEnum _ = Nothing + fromEnum false = 0 + fromEnum true = 1 --- | ## Instances +instance boundedEnumInt :: BoundedEnum Int where + cardinality = Cardinality (top - bottom) + toEnum = Just + fromEnum = id -instance enumUnit :: Enum Unit where - succ = const Nothing - pred = const Nothing +instance boundedEnumChar :: BoundedEnum Char where + cardinality = Cardinality (toCharCode top - toCharCode bottom) + toEnum = charToEnum + fromEnum = toCharCode instance boundedEnumUnit :: BoundedEnum Unit where cardinality = Cardinality 1 @@ -142,104 +172,68 @@ instance boundedEnumUnit :: BoundedEnum Unit where toEnum _ = Nothing fromEnum = const 0 -instance enumChar :: Enum Char where - succ = defaultSucc charToEnum charFromEnum - pred = defaultPred charToEnum charFromEnum - --- | To avoid a compiler bug - can't pass self-class functions, workaround: need to make a concrete function. -charToEnum :: Int -> Maybe Char -charToEnum n | n >= 0 && n <= 65535 = Just $ fromCharCode n -charToEnum _ = Nothing - -charFromEnum :: Char -> Int -charFromEnum = toCharCode - -instance boundedEnumChar :: BoundedEnum Char where - cardinality = Cardinality 65536 - toEnum = charToEnum - fromEnum = charFromEnum - --- TODO JB BoundedEnum is too restrictive on a, all we need is bottom -instance enumMaybe :: (BoundedEnum a) => Enum (Maybe a) where - succ Nothing = Just $ Just bottom - succ (Just a) = Just <$> succ a - pred Nothing = Nothing - pred (Just a) = Just $ pred a - -instance boundedEnumMaybe :: (BoundedEnum a) => BoundedEnum (Maybe a) where - cardinality = maybeCardinality cardinality - toEnum = maybeToEnum cardinality - fromEnum Nothing = zero - fromEnum (Just e) = fromEnum e + one - -maybeToEnum :: forall a. (BoundedEnum a) => Cardinality a -> Int -> Maybe (Maybe a) -maybeToEnum carda n | n <= runCardinality (maybeCardinality carda) = - if n == zero - then Just $ Nothing - else Just $ toEnum (n - one) -maybeToEnum _ _ = Nothing - -maybeCardinality :: forall a. (BoundedEnum a) => Cardinality a -> Cardinality (Maybe a) -maybeCardinality c = Cardinality $ one + (runCardinality c) - -instance enumBoolean :: Enum Boolean where - succ = booleanSucc - pred = booleanPred - -instance boundedEnumBoolean :: BoundedEnum Boolean where - cardinality = Cardinality 2 - toEnum = defaultToEnum booleanSucc bottom - fromEnum = defaultFromEnum booleanPred - -booleanSucc :: Boolean -> Maybe Boolean -booleanSucc false = Just true -booleanSucc _ = Nothing - -booleanPred :: Boolean -> Maybe Boolean -booleanPred true = Just false -booleanPred _ = Nothing +instance boundedEnumOrdering :: BoundedEnum Ordering where + cardinality = Cardinality 3 + toEnum 0 = Just LT + toEnum 1 = Just EQ + toEnum 2 = Just GT + toEnum _ = Nothing + fromEnum LT = 0 + fromEnum EQ = 1 + fromEnum GT = 2 + +instance boundedEnumMaybe :: BoundedEnum a => BoundedEnum (Maybe a) where + cardinality = Cardinality $ runCardinality (cardinality :: Cardinality a) + 1 + toEnum = to cardinality + where + to :: Cardinality a -> Int -> Maybe (Maybe a) + to _ 0 = Nothing + to (Cardinality ca) n | n <= ca = Just $ toEnum (n - 1) + to _ _ = Nothing + fromEnum Nothing = 0 + fromEnum (Just e) = fromEnum e + 1 -instance enumTuple :: (Enum a, BoundedEnum b) => Enum (Tuple a b) where - succ (Tuple a b) = maybe (flip Tuple bottom <$> succ a) (Just <<< Tuple a) (succ b) - pred (Tuple a b) = maybe (flip Tuple top <$> pred a) (Just <<< Tuple a) (pred b) +instance boundedEnumEither :: (BoundedEnum a, BoundedEnum b) => BoundedEnum (Either a b) where + cardinality = + Cardinality + $ runCardinality (cardinality :: Cardinality a) + + runCardinality (cardinality :: Cardinality b) + toEnum = to cardinality cardinality + where + to :: Cardinality a -> Cardinality (Either a b) -> Int -> Maybe (Either a b) + to (Cardinality ca) (Cardinality cab) n + | n >= 0 && n < ca = Left <$> toEnum n + | n >= ca && n < cab = Right <$> toEnum (n - ca) + | otherwise = Nothing + fromEnum (Left a) = fromEnum a + fromEnum (Right b) = fromEnum b + runCardinality (cardinality :: Cardinality a) instance boundedEnumTuple :: (BoundedEnum a, BoundedEnum b) => BoundedEnum (Tuple a b) where - cardinality = tupleCardinality cardinality cardinality - toEnum = tupleToEnum cardinality - fromEnum = tupleFromEnum cardinality + cardinality = + Cardinality + $ runCardinality (cardinality :: Cardinality a) + * runCardinality (cardinality :: Cardinality b) + toEnum = to cardinality + where + to :: Cardinality b -> Int -> Maybe (Tuple a b) + to (Cardinality cb) n = Tuple <$> toEnum (n / cb) <*> toEnum (n `mod` cb) + fromEnum = from cardinality + where + from :: Cardinality b -> Tuple a b -> Int + from (Cardinality cb) (Tuple a b) = fromEnum a * cb + fromEnum b --- | All of these are as a workaround for `ScopedTypeVariables`. (not yet supported in Purescript) -tupleToEnum :: forall a b. (BoundedEnum a, BoundedEnum b) => Cardinality b -> Int -> Maybe (Tuple a b) -tupleToEnum cardb n = Tuple <$> (toEnum (n / (runCardinality cardb))) <*> (toEnum (n `mod` (runCardinality cardb))) - -tupleFromEnum :: forall a b. (BoundedEnum a, BoundedEnum b) => Cardinality b -> Tuple a b -> Int -tupleFromEnum cardb (Tuple a b) = (fromEnum a) * runCardinality cardb + fromEnum 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) +-- | Runs in `O(n)` where `n` is `fromEnum top` +defaultCardinality :: forall a. (Bounded a, Enum a) => Cardinality a +defaultCardinality = Cardinality $ defaultCardinality' 1 (bottom :: a) where + defaultCardinality' i = maybe i (defaultCardinality' $ i + 1) <<< succ -instance enumEither :: (BoundedEnum a, BoundedEnum b) => Enum (Either a b) where - succ (Left a) = maybe (Just $ Right bottom) (Just <<< Left) (succ a) - succ (Right b) = maybe (Nothing) (Just <<< Right) (succ b) - pred (Left a) = maybe (Nothing) (Just <<< Left) (pred a) - pred (Right b) = maybe (Just $ Left top) (Just <<< Right) (pred b) + -- | Runs in `O(n)` where `n` is `fromEnum a` +defaultToEnum :: forall a. (Bounded a, Enum a) => Int -> Maybe a +defaultToEnum n + | n < 0 = Nothing + | n == 0 = Just bottom + | otherwise = defaultToEnum (n - 1) >>= succ -instance boundedEnumEither :: (BoundedEnum a, BoundedEnum b) => BoundedEnum (Either a b) where - cardinality = eitherCardinality cardinality cardinality - toEnum = eitherToEnum cardinality cardinality - fromEnum = eitherFromEnum cardinality - -eitherToEnum :: forall a b. (BoundedEnum a, BoundedEnum b) => Cardinality a -> Cardinality b -> Int -> Maybe (Either a b) -eitherToEnum carda cardb n = - if n >= zero && n < runCardinality carda - then Left <$> toEnum n - else if n >= (runCardinality carda) && n < runCardinality (eitherCardinality carda cardb) - then Right <$> toEnum (n - runCardinality carda) - else Nothing - -eitherFromEnum :: forall a b. (BoundedEnum a, BoundedEnum b) => Cardinality a -> (Either a b -> Int) -eitherFromEnum carda (Left a) = fromEnum a -eitherFromEnum carda (Right b) = fromEnum b + runCardinality carda - -eitherCardinality :: forall a b. (BoundedEnum a, BoundedEnum b) => Cardinality a -> Cardinality b -> Cardinality (Either a b) -eitherCardinality l r = Cardinality $ (runCardinality l) + (runCardinality r) + -- | Runs in `O(n)` where `n` is `fromEnum a` +defaultFromEnum :: forall a. Enum a => a -> Int +defaultFromEnum = maybe 0 (\prd -> defaultFromEnum prd + 1) <<< pred