music-score-1.7.2: src/Data/List/Ordered.hs
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE CPP #-}
module Data.List.Ordered where
import Control.Lens (Iso', iso, Prism', prism')
import Control.Applicative
import Control.Comonad
import Data.Functor.Couple
import Data.Ord (comparing)
import Data.List (takeWhile, sort, sortBy, group)
import Data.Maybe
import Data.Semigroup
import Control.Monad
import qualified Data.Set as Set
import qualified Data.Map as Map
import Numeric.Natural
-- TODO full definition
type Positive = Natural
-- TODO move
#ifndef GHCI
instance Comonad Min where
extract (Min x) = x
duplicate (Min x) = Min (Min x)
instance Comonad Max where
extract (Max x) = x
duplicate (Max x) = Max (Max x)
#endif
-- TODO move
-- TODO use positive
-- newtype Ordered a = Ordered { getOrdered :: Set.Set (a, Positive) }
-- OR
newtype Ordered a = Ordered { getOrdered :: {-Ord a =>-} Map.Map a Positive }
deriving ({-, Foldable, Traversable-})
instance (Ord a) => Eq (Ordered a) where
Ordered a == Ordered b = a == b
instance Ord a => Ord (Ordered a) where
Ordered a < Ordered b = a < b
-- | Alas, not a functor
map :: (Ord a, Ord b) => (a -> b) -> Ordered a -> Ordered b
map f (Ordered m) = Ordered (Map.mapKeys f m)
toList :: Ordered a -> [a]
toList (Ordered xs) = concatMap (uncurry $ flip $ replicate . fromIntegral) $ Map.toList xs
unsafeFromList :: Ord a => [a] -> Ordered a
unsafeFromList = fromMaybe (error "unsafeFromList: Not sorted") . fromList
-- Safe (but slow) conversion from lists to ordered lists
fromList :: Ord a => [a] -> Maybe (Ordered a)
fromList xs
| xs /= sort xs = Nothing
| otherwise = Just $ Ordered $ Map.fromList $
Prelude.map (\x -> (head x, fromIntegral $ Prelude.length x)) $ group xs
-- Safe (but slow) prism from lists to ordered lists
ordered :: Ord a => Prism' [a] (Ordered a)
ordered = prism' toList fromList
{-
where
prism' bs sma = prism bs (\s -> maybe (Left s) Right (sma s))
prism bt seta = dimap seta (either pure (fmap bt)) . right'
-}
unsafeOrdered :: Ord a => Iso' [a] (Ordered a)
unsafeOrdered = iso unsafeFromList toList
{-
where
iso sa bt = dimap sa (fmap bt)
-}
elem :: Ord a => a -> Ordered a -> Bool
elem k = (> 0) . occs k
occs :: Ord a => a -> Ordered a -> Int
occs k = maybe 0 fromIntegral . Map.lookup k . getOrdered
null :: Ordered k -> Bool
null = Map.null . getOrdered
length :: Ordered a -> Int
length = Prelude.length . toList
-- elem x (Ordered xs) = x