countable-1.1: src/Data/Countable.hs
module Data.Countable where
import Data.Int
import Data.Void
import Data.Word
import Prelude
-- | Values form a possibly empty, possibly finite, countable sequence.
class Eq a => Countable a where
countPrevious :: a -> Maybe a
countMaybeNext :: Maybe a -> Maybe a
countDown :: (Countable a) => a -> [a]
countDown a =
case countPrevious a of
Just a' -> a' : (countDown a')
Nothing -> []
instance Countable Void where
countPrevious = absurd
countMaybeNext Nothing = Nothing
countMaybeNext (Just n) = absurd n
instance Countable () where
countPrevious () = Nothing
countMaybeNext Nothing = Just ()
countMaybeNext (Just ()) = Nothing
instance Countable Bool where
countPrevious True = Just False
countPrevious False = Nothing
countMaybeNext Nothing = Just False
countMaybeNext (Just False) = Just True
countMaybeNext (Just True) = Nothing
boundedCountPrevious :: (Eq a, Bounded a, Enum a) => a -> Maybe a
boundedCountPrevious n
| n == minBound = Nothing
boundedCountPrevious n = Just (pred n)
boundedCountMaybeNext :: (Eq a, Bounded a, Enum a) => Maybe a -> Maybe a
boundedCountMaybeNext Nothing = Just minBound
boundedCountMaybeNext (Just n)
| n == maxBound = Nothing
boundedCountMaybeNext (Just n) = Just (succ n)
instance Countable Word8 where
countPrevious = boundedCountPrevious
countMaybeNext = boundedCountMaybeNext
instance Countable Word16 where
countPrevious = boundedCountPrevious
countMaybeNext = boundedCountMaybeNext
instance Countable Word32 where
countPrevious = boundedCountPrevious
countMaybeNext = boundedCountMaybeNext
instance Countable Word64 where
countPrevious = boundedCountPrevious
countMaybeNext = boundedCountMaybeNext
instance Countable Int8 where
countPrevious = boundedCountPrevious
countMaybeNext = boundedCountMaybeNext
instance Countable Int16 where
countPrevious = boundedCountPrevious
countMaybeNext = boundedCountMaybeNext
instance Countable Int32 where
countPrevious = boundedCountPrevious
countMaybeNext = boundedCountMaybeNext
instance Countable Int64 where
countPrevious = boundedCountPrevious
countMaybeNext = boundedCountMaybeNext
instance Countable Integer where
countPrevious 0 = Nothing
countPrevious a
| a < 0 = Just (-a - 1)
countPrevious a = Just (-a)
countMaybeNext = Just . countNext
instance (Countable a) => Countable (Maybe a) where
countPrevious = fmap countPrevious
countMaybeNext Nothing = Just Nothing
countMaybeNext (Just ma) = fmap Just (countMaybeNext ma)
maybeRecount :: (Countable a, Countable b) => a -> Maybe b
maybeRecount a =
case countPrevious a of
Just a' -> do
b' <- maybeRecount a'
countMaybeNext b'
Nothing -> countMaybeNext Nothing
{-
Right 0
Left 0
Right 1
Left 1
Left 2
Left 3
-}
instance (Countable a, Countable b) => Countable (Either a b) where
countPrevious (Right b) =
case countPrevious b of
Just b' ->
case maybeRecount b' of
Just a -> Just (Left a)
Nothing -> Just (Right b)
Nothing -> Nothing
countPrevious (Left a) =
case maybeRecount a of
Just b -> Just (Right b)
Nothing -> fmap Left (countPrevious a)
countMaybeNext Nothing =
case countMaybeNext Nothing of
Just b -> Just (Right b)
Nothing -> fmap Left (countMaybeNext Nothing)
countMaybeNext (Just (Right b)) =
case maybeRecount b of
Just a -> Just (Left a)
Nothing -> fmap Right (countMaybeNext (Just b))
countMaybeNext (Just (Left a)) =
case maybeRecount a >>= (countMaybeNext . Just) of
Just b -> (Just (Right b))
Nothing -> fmap Left (countMaybeNext (Just a))
countDownUp :: (Countable down, Countable up) => (down, up) -> Maybe (down, up)
countDownUp (down, up) = do
down' <- countPrevious down
up' <- countMaybeNext (Just up)
return (down', up')
countUpDown :: (Countable up, Countable down) => (up, down) -> Maybe (up, down)
countUpDown (up, down) = do
up' <- countMaybeNext (Just up)
down' <- countPrevious down
return (up', down')
finalIteration :: (a -> Maybe a) -> a -> a
finalIteration f a =
case f a of
Just a' -> finalIteration f a'
Nothing -> a
instance (Countable a, Countable b) => Countable (a, b) where
countPrevious ab =
case countUpDown ab of
Just ab' -> Just ab'
_ -> let
(a', b') = finalIteration countDownUp ab
in case countPrevious a' of
Just a'' -> Just (a'', b')
Nothing ->
case countPrevious b' of
Just b'' -> Just (a', b'')
Nothing -> Nothing
countMaybeNext Nothing = do
a <- countMaybeNext Nothing
b <- countMaybeNext Nothing
return (a, b)
countMaybeNext (Just ab) =
case countDownUp ab of
Just ab' -> Just ab'
_ -> let
(a', b') = finalIteration countUpDown ab
in case countMaybeNext (Just a') of
Just a'' -> Just (a'', b')
Nothing ->
case countMaybeNext (Just b') of
Just b'' -> Just (a', b'')
Nothing -> Nothing
-- | Values form a non-empty, possibly finite, countable sequence.
class Countable a => AtLeastOneCountable a where
countFirst :: a
instance AtLeastOneCountable () where
countFirst = ()
instance AtLeastOneCountable Bool where
countFirst = False
instance AtLeastOneCountable Word8 where
countFirst = minBound
instance AtLeastOneCountable Word16 where
countFirst = minBound
instance AtLeastOneCountable Word32 where
countFirst = minBound
instance AtLeastOneCountable Word64 where
countFirst = minBound
instance AtLeastOneCountable Int8 where
countFirst = minBound
instance AtLeastOneCountable Int16 where
countFirst = minBound
instance AtLeastOneCountable Int32 where
countFirst = minBound
instance AtLeastOneCountable Int64 where
countFirst = minBound
instance AtLeastOneCountable Integer where
countFirst = 0
instance (Countable a) => AtLeastOneCountable (Maybe a) where
countFirst = Nothing
instance (Countable a, AtLeastOneCountable b) => AtLeastOneCountable (Either a b) where
countFirst = Right countFirst
instance (AtLeastOneCountable a, AtLeastOneCountable b) => AtLeastOneCountable (a, b) where
countFirst = (countFirst, countFirst)
-- | Values form an infinite countable sequence.
class (AtLeastOneCountable a) => InfiniteCountable a where
countNext :: Maybe a -> a
instance InfiniteCountable Integer where
countNext Nothing = 0
countNext (Just a)
| a < 0 = -a
countNext (Just a) = -a - 1
instance (InfiniteCountable a) => InfiniteCountable (Maybe a) where
countNext = fmap countNext
instance (AtLeastOneCountable a, InfiniteCountable b) => InfiniteCountable (a, b) where
countNext Nothing = (countFirst, countNext Nothing)
countNext (Just ab) =
case countDownUp ab of
Just ab' -> ab'
_ -> let
(a', b') = finalIteration countUpDown ab
in case countMaybeNext (Just a') of
Just a'' -> (a'', b')
Nothing -> (a', countNext (Just b'))
recount :: (Countable a, InfiniteCountable b) => a -> b
recount = countNext . (fmap recount) . countPrevious
instance (Countable a, InfiniteCountable b) => InfiniteCountable (Either a b) where
countNext Nothing = Right (countNext Nothing)
countNext (Just (Right b)) =
case maybeRecount b of
Just a -> Left a
Nothing -> Right (countNext (Just b))
countNext (Just (Left a)) = Right (countNext (recount a))
instance (Countable a) => Countable [a] where
countPrevious [] = Nothing
countPrevious (x:xs) =
case countMaybeNext Nothing of
Nothing -> seq x undefined -- x not supposed to exist
Just firsta -> Just (pp x xs)
where pp a r =
case countPrevious a of
Just a' -> firsta : (pp a' r)
Nothing ->
case r of
[] -> []
b:r' ->
case countMaybeNext (Just b) of
Just b' -> b' : r'
Nothing -> firsta : (pp b r')
countMaybeNext Nothing = Just []
countMaybeNext (Just l) =
case countMaybeNext Nothing of
Nothing -> Nothing
Just firsta -> Just (countNext' l)
where countNext' [] = [firsta]
countNext' (a:r) =
case countPrevious a of
Just a' -> firsta : a' : r
Nothing -> upOne (countNext' r)
upOne [] = [firsta]
upOne (a:r) =
case countMaybeNext (Just a) of
Just a' -> a' : r
Nothing -> firsta : a : r
instance (Countable a) => AtLeastOneCountable [a] where
countFirst = []
instance (AtLeastOneCountable a) => InfiniteCountable [a] where
countNext Nothing = []
countNext (Just l) = countNext' l
where
countNext' [] = [countFirst]
countNext' (a:r) =
case countPrevious a of
Just a' -> countFirst : a' : r
Nothing -> upOne (countNext' r)
upOne [] = [countFirst]
upOne (a:r) =
case countMaybeNext (Just a) of
Just a' -> a' : r
Nothing -> countFirst : a : r