module Data.Functor.Selection
(
Selection(..)
, Selection'
, modifySelection
, newSelection
, forgetSelection
, select
, include
, exclude
, selectAll
, deselectAll
, invertSelection
, mapSelected
, mapUnselected
, getSelected
, getUnselected
, unify
, trans
, selectWithContext
) where
import Control.Monad (ap)
import Control.Comonad (Comonad(..))
import Data.Bifoldable (Bifoldable(..))
import Data.Bifunctor (Bifunctor(..))
import Data.Bitraversable (Bitraversable(..))
newtype Selection f b a = Selection
{
unwrapSelection :: f (Either b a)
} deriving (Functor, Foldable, Traversable)
type Selection' f a = Selection f a a
deriving instance (Show (f (Either b a))) => Show (Selection f b a)
deriving instance (Eq (f (Either b a))) => Eq (Selection f b a)
instance Monad m => Applicative (Selection m b) where
pure = Selection . pure . Right
(<*>) = ap
instance (Monad m) => Monad (Selection m b) where
return = pure
Selection m >>= k =
Selection $ m >>= either (return . Left) (unwrapSelection . k)
instance (Functor f) => Bifunctor (Selection f) where
first f = Selection . fmap (first f) . unwrapSelection
second = fmap
instance (Foldable f) => Bifoldable (Selection f) where
bifoldMap l r = foldMap (bifoldMap l r) . unwrapSelection
instance (Traversable f) => Bitraversable (Selection f) where
bitraverse l r = fmap Selection . traverse (bitraverse l r) . unwrapSelection
modifySelection :: (Functor f) => (f (Either b a) -> g (Either d c)) -> Selection f b a -> Selection g d c
modifySelection f = Selection . f . unwrapSelection
newSelection :: (Functor f) => f a -> Selection f b a
newSelection = Selection . fmap Right
forgetSelection :: (Functor f) => Selection f a a -> f a
forgetSelection = unify id id
select :: (Functor f) => (a -> Bool) -> Selection f a a -> Selection f a a
select f = include f . deselectAll
include :: (Functor f) => (a -> Bool) -> Selection f a a -> Selection f a a
include f = modifySelection (fmap (either (choose f) Right))
exclude :: (Functor f) => (a -> Bool) -> Selection f a a -> Selection f a a
exclude f = modifySelection (fmap (either Left (switch . choose f)))
selectAll :: (Functor f) => Selection f a a -> Selection f a a
selectAll = include (const True)
deselectAll :: (Functor f) => Selection f a a -> Selection f a a
deselectAll = exclude (const True)
invertSelection :: (Functor f) => Selection f b a -> Selection f a b
invertSelection = modifySelection (fmap switch)
mapSelected :: (Functor f) => (a -> c) -> Selection f b a -> Selection f b c
mapSelected = fmap
mapUnselected :: (Functor f) => (b -> c) -> Selection f b a -> Selection f c a
mapUnselected = first
getSelected :: (Foldable f) => Selection f b a -> [a]
getSelected = foldMap (:[])
getUnselected :: (Foldable f, Functor f) => Selection f b a -> [b]
getUnselected = bifoldMap (:[]) (const [])
unify :: (Functor f) => (b -> c) -> (a -> c) -> Selection f b a -> f c
unify l r = fmap (either l r) . unwrapSelection
trans :: (Functor f) => (forall c. f c -> g c) -> Selection f b a -> Selection g b a
trans f = modifySelection f
selectWithContext :: (Comonad w) => (w a -> Bool) -> Selection w a a -> Selection w a a
selectWithContext f = modifySelection (extend (choose' extract f) . fmap (either id id))
choose' :: (a -> b) -> (a -> Bool) -> a -> Either b b
choose' f p a = if p a then Right (f a)
else Left (f a)
choose :: (a -> Bool) -> a -> Either a a
choose = choose' id
switch :: Either a b -> Either b a
switch = either Right Left