{-# LANGUAGE ScopedTypeVariables #-} {- | Module : Data.IxSet.Typed.Conversions License : MIT Stability : experimental Conversions from ixset-typed to other containers. -} module Data.IxSet.Typed.Conversions ( toHashMap , toHashMapBy , toHashMapByM , toHashMapBy' , toHashMapByM' , toZipperAsc , toZipperDesc , toAscCofreeList , toAscCofreeListM , toDescCofreeList , toDescCofreeListM ) where import Control.Applicative import Control.Comonad.Cofree import Control.Comonad.Zipper.Extra import Control.Monad import Control.Monad.Catch import Data.Hashable import qualified Data.HashMap.Strict as HM import qualified Data.List as L import Data.IxSet.Typed as Ix import Data.Proxy -- | Convert an `IxSet to a `HashMap`. toHashMap :: (Hashable a, IsIndexOf a xs) => IxSet xs k -> HM.HashMap a [k] toHashMap = HM.fromList . Ix.groupDescBy -- | Convert an `IxSet` to a `HashMap` via a function on the index and associated list. toHashMapBy :: (Hashable a, IsIndexOf a xs) => IxSet xs k -> (a -> [k] -> k') -> HM.HashMap a k' toHashMapBy xs f = HM.fromList $ flip map (Ix.groupDescBy xs) $ \(a, ks) -> (a, f a ks) -- | Monadic variant of `toHashMapBy`. toHashMapByM :: (Monad m, Hashable a, IsIndexOf a xs) => IxSet xs k -> (a -> [k] -> m k') -> m (HM.HashMap a k') toHashMapByM xs f = fmap HM.fromList $ forM (Ix.groupDescBy xs) $ \(a, ks) -> do z <- f a ks return (a, z) -- | Like `toHashMapBy`, but uses a function on the requeried `IxSet` for that key. toHashMapBy' :: (Hashable a, IsIndexOf a xs, Indexable xs k) => IxSet xs k -> (a -> IxSet xs k -> k') -> HM.HashMap a k' toHashMapBy' xs f = HM.fromList $ flip map (Ix.indexKeys xs) $ \a -> (a, f a (xs Ix.@+ [a])) -- | Like `toHashMapByM`, but uses a function on the requeried `IxSet` for that key. toHashMapByM' :: (Monad m, Hashable a, IsIndexOf a xs, Indexable xs k) => Ix.IxSet xs k -> (a -> Ix.IxSet xs k -> m k') -> m (HM.HashMap a k') toHashMapByM' xs f = fmap HM.fromList $ forM (Ix.indexKeys xs) $ \a -> do z <- f a (xs Ix.@+ [a]) return (a, z) -- | Convert an `IxSet` to a `Zipper` by descending sort on an index. toZipperAsc :: forall proxy ix ixs a m. (IsIndexOf ix ixs, MonadThrow m) => proxy ix -> IxSet ixs a -> m (Zipper [] a) toZipperAsc _ = zipper' . Ix.toAscList (Proxy :: Proxy ix) -- | Convert an `IxSet` to a `Zipper` by descending sort on an index. toZipperDesc :: forall proxy ix ixs a m. (IsIndexOf ix ixs, MonadThrow m) => proxy ix -> IxSet ixs a -> m (Zipper [] a) toZipperDesc _ = zipper' . Ix.toDescList (Proxy :: Proxy ix) -- | Convert an `IxSet` to a list of `Cofree` by grouping on one of its indices. The result will be sorted in ascending -- order on the index. The elements will be sorted according to the `Ord` instance on b. toAscCofreeList :: (Ord b, Ix.IsIndexOf ix ixs) => (ix -> c) -> (a -> c) -> (a -> b) -> Ix.IxSet ixs a -> [Cofree [] c] toAscCofreeList f g h xs = flip map (Ix.groupAscBy xs) $ \(x, as) -> f x :< map ((:< []) . g) (L.sortOn h as) -- | Monadic version of `toAscCofreeList`. toAscCofreeListM :: (Ord b, Ix.IsIndexOf ix ixs, Monad m) => (ix -> m c) -> (a -> c) -> (a -> b) -> Ix.IxSet ixs a -> m [Cofree [] c] toAscCofreeListM f g h xs = forM (Ix.groupAscBy xs) $ \(x, as) -> liftA2 (:<) (f x) (return $ map ((:< []) . g) (L.sortOn h as)) -- | Convert an `IxSet` to a list of `Cofree` by grouping on one of its indices. The result will be sorted in descending -- order on the index. The elements will be sorted according to the `Ord` instance on b. toDescCofreeList :: (Ord b, Ix.IsIndexOf ix ixs) => (ix -> c) -> (a -> c) -> (a -> b) -> Ix.IxSet ixs a -> [Cofree [] c] toDescCofreeList f g h xs = flip map (Ix.groupDescBy xs) $ \(x, as) -> f x :< map ((:< []) . g) (L.sortOn h as) -- | Monadic version of `toDescCofreeList`. toDescCofreeListM :: (Ord b, Ix.IsIndexOf ix ixs, Monad m) => (ix -> m c) -> (a -> c) -> (a -> b) -> Ix.IxSet ixs a -> m [Cofree [] c] toDescCofreeListM f g h xs = forM (Ix.groupDescBy xs) $ \(x, as) -> liftA2 (:<) (f x) (return $ map ((:< []) . g) (L.sortOn h as))