module Data.Meep
#ifdef TEST
( Meep(..)
#else
( Meep
#endif
, empty
, singleton
, size
, null
, fromMaybe
, toMaybe
, maybeing
, keys
, elems
) where
import Control.Applicative (pure, liftA2)
import Control.Lens
import Data.Bifoldable (Bifoldable(..))
import Data.Bifunctor.Apply (Biapply(..))
import Data.Bitraversable (Bitraversable(..))
import Data.Monoid (mempty)
import Data.Data (Data, Typeable)
import Data.Foldable (Foldable)
import Data.Semigroup (Semigroup(..), Monoid(..))
import GHC.Generics (Generic)
import Prelude hiding (null, lookup)
#ifdef TEST
import Test.QuickCheck (Arbitrary(..))
#endif
data Meep k a = Empty | Meep !k a
deriving (Eq, Ord, Functor, Foldable, Traversable, Typeable, Data, Generic)
instance (Show k, Show a) => Show (Meep k a) where
showsPrec p m = showParen (p > 10) (showString "fromMaybe " . shows (toMaybe m))
instance (Eq k, Semigroup a) => Semigroup (Meep k a) where
Empty <> _ = Empty
_ <> Empty = Empty
Meep k v <> Meep k' v' = bool Empty (Meep k (v <> v')) (k == k')
instance Bifunctor Meep where
bimap _ _ Empty = Empty
bimap f g (Meep k v) = Meep (f k) (g v)
instance Biapply Meep where
Empty <<.>> _ = Empty
_ <<.>> Empty = Empty
Meep fk fv <<.>> Meep k v = Meep (fk k) (fv v)
instance Bifoldable Meep where
bifoldMap _ _ Empty = mempty
bifoldMap f g (Meep k v) = f k `mappend` g v
instance Bitraversable Meep where
bitraverse _ _ Empty = pure Empty
bitraverse f g (Meep k v) = liftA2 Meep (f k) (g v)
instance Eq k => Ixed (Meep k a) where
ix = ixAt
instance Eq k => At (Meep k a) where
at k f m = indexed f k mv <&> \r -> case r of
Nothing -> maybe m (const (delete k m)) mv
Just v -> insert k v m
where
mv = lookup k m
type instance Index (Meep k a) = k
type instance IxValue (Meep k a) = a
instance FunctorWithIndex k (Meep k) where
imap _ Empty = Empty
imap f (Meep k a) = Meep k (f k a)
instance FoldableWithIndex k (Meep k) where
ifoldMap _ Empty = mempty
ifoldMap f (Meep k a) = f k a
instance TraversableWithIndex k (Meep k) where
itraverse _ Empty = pure Empty
itraverse f (Meep k a) = fmap (Meep k) (f k a)
instance AsEmpty (Meep k a) where
_Empty = prism' (const Empty) (\x -> case x of Empty -> Just (); _ -> Nothing)
#ifdef TEST
instance (Arbitrary k, Arbitrary a) => Arbitrary (Meep k a) where
arbitrary = fmap fromMaybe arbitrary
#endif
empty :: Meep k a
empty = Empty
singleton :: k -> a -> Meep k a
singleton = Meep
size :: Num b => Meep k a -> b
size = bool 1 0 . null
null :: Meep k a -> Bool
null Empty = True
null (Meep _ _) = False
fromMaybe :: Maybe (k, a) -> Meep k a
fromMaybe = maybe Empty (uncurry Meep)
toMaybe :: Meep k a -> Maybe (k, a)
toMaybe Empty = Nothing
toMaybe (Meep k a) = Just (k, a)
maybeing :: Iso (Meep k v) (Meep k' v') (Maybe (k, v)) (Maybe (k', v'))
maybeing = iso toMaybe fromMaybe
keys :: Meep k a -> Maybe k
keys Empty = Nothing
keys (Meep k _) = Just k
elems :: Meep k a -> Maybe a
elems Empty = Nothing
elems (Meep _ a) = Just a
insert :: Eq k => k -> a -> Meep k a -> Meep k a
insert k a Empty = Meep k a
insert k a x@(Meep k' _) = bool x (Meep k a) (k == k')
lookup :: Eq k => k -> Meep k a -> Maybe a
lookup _ Empty = Nothing
lookup k' (Meep k a) = bool Nothing (Just a) (k == k')
delete :: Eq k => k -> Meep k a -> Meep k a
delete _ Empty = Empty
delete k' x@(Meep k _) = bool x Empty (k == k')
bool :: a -> a -> Bool -> a
bool f t p = if p then t else f