-- | Enumeration functions.
module Music.Theory.Enum where

import Data.List {- base -}

-- | Generic variant of 'fromEnum' (p.263).
genericFromEnum :: (Integral i,Enum e) => e -> i
genericFromEnum :: forall i e. (Integral i, Enum e) => e -> i
genericFromEnum = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Enum a => a -> Int
fromEnum

-- | Generic variant of 'toEnum' (p.263).
genericToEnum :: (Integral i,Enum e) => i -> e
genericToEnum :: forall i e. (Integral i, Enum e) => i -> e
genericToEnum = forall a. Enum a => Int -> a
toEnum forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral

-- | Variant of 'enumFromTo' that, if /p/ is after /q/, cycles from
-- 'maxBound' to 'minBound'.
--
-- > import Data.Word
-- > enum_from_to_cyclic (254 :: Word8) 1 == [254,255,0,1]
enum_from_to_cyclic :: (Bounded a, Enum a) => a -> a -> [a]
enum_from_to_cyclic :: forall a. (Bounded a, Enum a) => a -> a -> [a]
enum_from_to_cyclic a
p a
q =
    if forall a. Enum a => a -> Int
fromEnum a
p forall a. Ord a => a -> a -> Bool
> forall a. Enum a => a -> Int
fromEnum a
q
    then [a
p .. forall a. Bounded a => a
maxBound] forall a. [a] -> [a] -> [a]
++ [forall a. Bounded a => a
minBound .. a
q]
    else [a
p .. a
q]

-- | Variant of 'enumFromTo' that, if /p/ is after /q/, enumerates
-- from /q/ to /p/.
--
-- > enum_from_to_reverse 5 1 == [5,4,3,2,1]
-- > enum_from_to_reverse 1 5 == enumFromTo 1 5
enum_from_to_reverse :: Enum a => a -> a -> [a]
enum_from_to_reverse :: forall a. Enum a => a -> a -> [a]
enum_from_to_reverse a
p a
q =
    if forall a. Enum a => a -> Int
fromEnum a
p forall a. Ord a => a -> a -> Bool
> forall a. Enum a => a -> Int
fromEnum a
q
    then forall a. [a] -> [a]
reverse [a
q .. a
p]
    else [a
p .. a
q]

-- | All elements in sequence.
--
-- > (enum_univ :: [Data.Word.Word8]) == [0 .. 255]
enum_univ :: (Bounded t,Enum t) => [t]
enum_univ :: forall t. (Bounded t, Enum t) => [t]
enum_univ = [forall a. Bounded a => a
minBound .. forall a. Bounded a => a
maxBound]

-- | List of 'Enum' values not in sorted input list.
--
-- > enum_list_gaps "abdh" == "cefg"
enum_list_gaps :: (Enum t,Eq t) => [t] -> [t]
enum_list_gaps :: forall t. (Enum t, Eq t) => [t] -> [t]
enum_list_gaps [t]
l =
  let e0 :: t
e0 = forall a. [a] -> a
head [t]
l
      eN :: t
eN = forall a. [a] -> a
last [t]
l
      f :: t -> Bool
f t
x = t
x forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [t]
l
  in forall a. (a -> Bool) -> [a] -> [a]
filter t -> Bool
f [t
e0 .. t
eN]

-- | 'enum_list_gaps' of 'sort'
enum_set_gaps :: (Enum t,Eq t,Ord t) => [t] -> [t]
enum_set_gaps :: forall t. (Enum t, Eq t, Ord t) => [t] -> [t]
enum_set_gaps = forall t. (Enum t, Eq t) => [t] -> [t]
enum_list_gaps forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Ord a => [a] -> [a]
sort