packages feed

rest-rewrite-0.1: src/Language/REST/MultiSet.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}

module Language.REST.MultiSet
  ( MultiSet
  , delete
  , deleteMany
  , distinctElems
  , empty
  , filter
  , insert
  , member
  , null
  , toList
  , toOccurList
  , singleton
  , fromList
  , toSet
  ) where

import Prelude hiding (null, filter, delete)

import GHC.Generics
import Data.Hashable
import qualified Data.List as L
import qualified Data.HashMap.Strict as M
import qualified Data.HashSet as S

data MultiSet a = MultiSet (M.HashMap a Int) deriving (Eq, Generic, Hashable, Ord)

instance Show a => Show (MultiSet a) where
  show ms = "{" ++ L.intercalate ", " (map show $ toList ms) ++ "}"

delete :: (Hashable a, Eq a) => a -> MultiSet a -> MultiSet a
delete k = deleteMany k 1

deleteMany :: (Hashable a, Eq a) => a -> Int -> MultiSet a -> MultiSet a
deleteMany k v (MultiSet ms) | Just c <- M.lookup k ms
                             , c > v = MultiSet $ M.insert k (c - v) ms
deleteMany k _ (MultiSet ms) | otherwise = MultiSet $ M.delete k ms

distinctElems :: MultiSet a -> [a]
distinctElems (MultiSet ms) = M.keys ms

empty :: MultiSet a
empty = MultiSet M.empty

toOccurList :: MultiSet a -> [(a, Int)]
toOccurList (MultiSet ms) = M.toList ms

filter :: (a -> Bool) -> MultiSet a -> MultiSet a
filter f (MultiSet ms) = MultiSet $ M.filterWithKey f' ms
  where
    f' k _ = f k

null :: MultiSet a -> Bool
null (MultiSet ms) = M.null ms

member :: (Eq a, Hashable a) => a -> MultiSet a -> Bool
member k (MultiSet ms) = M.member k ms

toList :: MultiSet a -> [a]
toList ms = concatMap go (toOccurList ms)
  where
    go (k, num) = take num $ repeat k

insert :: (Eq a, Hashable a) => a -> MultiSet a -> MultiSet a
insert k (MultiSet ms) | Just c <- M.lookup k ms
                       = MultiSet $ M.insert k (c + 1) ms
insert k (MultiSet ms) | otherwise
                       = MultiSet $ M.insert k 1 ms

singleton :: (Eq a, Hashable a) => a -> MultiSet a
singleton k = MultiSet (M.singleton k 1)

fromList  :: (Eq a, Hashable a) => [a] -> MultiSet a
fromList = foldl (flip insert) empty

toSet :: MultiSet a -> S.HashSet a
toSet (MultiSet ms) = M.keysSet ms