module Data.Functor.Selection
(
SelectionT(..)
, newSelection
, forgetSelection
, select
, include
, exclude
, selectAll
, deselectAll
, invertSelection
, onSelected
, onUnselected
, getSelected
, getUnselected
, selectWithContext
) where
import Control.Comonad (Comonad(..))
import Control.Monad.Trans
import Data.Bifoldable (Bifoldable(..))
import Data.Bifunctor (Bifunctor(..))
import Data.Bitraversable (Bitraversable(..))
newtype SelectionT f b a = SelectionT {
runSelectionT :: f (Either b a)
} deriving (Functor, Foldable)
deriving instance (Eq (f (Either b a))) => Eq (SelectionT f b a)
deriving instance (Show (f (Either b a))) => Show (SelectionT f b a)
instance (Applicative f) => Applicative (SelectionT f b) where
pure = SelectionT . pure . pure
SelectionT fa <*> SelectionT ga = SelectionT ((<*>) <$> fa <*> ga)
instance (Monad f) => Monad (SelectionT f b) where
return = pure
SelectionT m >>= k =
SelectionT $ m >>= either (return . Left) (runSelectionT . k)
instance (Functor f) => Bifunctor (SelectionT f) where
first f = SelectionT . fmap (first f) . runSelectionT
second = fmap
instance (Foldable f) => Bifoldable (SelectionT f) where
bifoldMap l r = foldMap (bifoldMap l r) . runSelectionT
instance (Traversable f) => Bitraversable (SelectionT f) where
bitraverse l r = fmap SelectionT . traverse (bitraverse l r) . runSelectionT
newSelection :: (Functor f) => f a -> SelectionT f () a
newSelection = SelectionT . fmap Right
forgetSelection :: Functor f => SelectionT f a a -> f a
forgetSelection = fmap (either id id) . runSelectionT
select :: Functor f => (a -> Bool) -> SelectionT f a a -> SelectionT f a a
select f = include f . deselectAll
include :: Functor f => (a -> Bool) -> SelectionT f a a -> SelectionT f a a
include f = SelectionT . fmap (either (choose f) Right) . runSelectionT
exclude :: Functor f => (a -> Bool) -> SelectionT f a a -> SelectionT f a a
exclude f = SelectionT . fmap (either Left (switch . choose f)) . runSelectionT
selectAll :: (Functor f) => SelectionT f a a -> SelectionT f a a
selectAll = include (const True)
deselectAll :: (Functor f) => SelectionT f a a -> SelectionT f a a
deselectAll = exclude (const True)
invertSelection :: Functor f => SelectionT f b a -> SelectionT f a b
invertSelection = SelectionT . fmap switch . runSelectionT
onSelected :: Functor f => (a -> c) -> SelectionT f b a -> SelectionT f b c
onSelected = fmap
onUnselected :: Functor f => (b -> c) -> SelectionT f b a -> SelectionT f c a
onUnselected = first
getSelected :: Foldable f => SelectionT f b a -> [a]
getSelected = foldMap (:[])
getUnselected :: (Functor f, Foldable f) => SelectionT f b a -> [b]
getUnselected = foldMap (:[]) . invertSelection
selectWithContext :: Comonad w => (w a -> Bool) -> SelectionT w a a -> SelectionT w a a
selectWithContext f = SelectionT . extend (choose' extract f) . forgetSelection
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