{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ViewPatterns #-}
#ifdef TESTING
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE QuantifiedConstraints #-}
#endif
module Shpadoinkle.Widgets.Types.Choice where
import Control.Compactable (Compactable (compact, filter, partition, separate))
import Data.Aeson (FromJSON, ToJSON)
import qualified Data.Foldable as F
import Data.Functor.Classes (Eq1 (..), Ord1 (..))
import Data.Kind (Type)
import qualified Data.List.NonEmpty as NE
import Data.Proxy
import Data.Set as Set
import GHC.Generics (Generic)
import Shpadoinkle (NFData)
#ifdef TESTING
import Data.Monoid (Sum (..))
import Test.QuickCheck
import Test.QuickCheck.Classes
import Test.QuickCheck.Classes.Hspec
import Test.QuickCheck.Classes.Internal (eq1, func1, func2)
#endif
data Pick = One | AtleastOne | Many
deriving (Eq, Ord, Show, Generic, NFData)
type family Selected (p :: Pick) (a :: Type) :: Type where
Selected 'One a = Maybe a
Selected 'AtleastOne a = a
Selected 'Many a = Set a
data Choice (p :: Pick) a = Choice
{ _selected :: Selected p a
, _options :: Set a
}
deriving instance (Show (Selected p a), Show a) => Show (Choice p a)
deriving instance (Read (Selected p a), Read a, Ord a) => Read (Choice p a)
deriving instance (Eq (Selected p a), Eq a) => Eq (Choice p a)
deriving instance (Ord (Selected p a), Ord a) => Ord (Choice p a)
deriving instance Generic (Choice p a)
instance (NFData (Selected p a), NFData a) => NFData (Choice p a)
instance (ToJSON (Selected p a), ToJSON a) => ToJSON (Choice p a)
instance (FromJSON (Selected p a), FromJSON a, Ord a) => FromJSON (Choice p a)
class DemotePick (p :: Pick) where demotePick :: Pick
instance DemotePick 'One where demotePick = One
instance DemotePick 'AtleastOne where demotePick = AtleastOne
instance DemotePick 'Many where demotePick = Many
instance Eq1 (Choice 'One) where
liftEq f (Choice s o) (Choice s' o') = liftEq f s s' && liftEq f o o'
instance Eq1 (Choice 'AtleastOne) where
liftEq f (Choice s o) (Choice s' o') = f s s' && liftEq f o o'
instance Eq1 (Choice 'Many) where
liftEq f (Choice s o) (Choice s' o') = liftEq f s s' && liftEq f o o'
instance Ord1 (Choice 'One) where
liftCompare f (Choice s o) (Choice s' o') = liftCompare f s s' `compare` liftCompare f o o'
instance Ord1 (Choice 'AtleastOne) where
liftCompare f (Choice s o) (Choice s' o') = f s s' `compare` liftCompare f o o'
instance Ord1 (Choice 'Many) where
liftCompare f (Choice s o) (Choice s' o') = liftCompare f s s' `compare` liftCompare f o o'
instance (Bounded a, Enum a) => Bounded (Choice 'AtleastOne a) where
minBound = Choice minBound fullset
maxBound = Choice maxBound fullset
instance (Bounded a, Enum a) => Enum (Choice 'AtleastOne a) where
toEnum n = Choice (toEnum n) fullset
fromEnum (Choice x _) = fromEnum x
instance Foldable (Choice 'One) where foldr f x (Choice y xs) = Set.foldr f (Prelude.foldr f x y) xs
instance Foldable (Choice 'AtleastOne) where foldr f x (Choice y xs) = Set.foldr f (f y x) xs
instance Foldable (Choice 'Many) where foldr f x (Choice y xs) = Set.foldr f (Set.foldr f x y) xs
instance (Semigroup a, Ord a) => Semigroup (Choice 'One a)
where Choice x xs <> Choice y ys = Choice (x <> y) (xs <> ys)
instance (Semigroup a, Ord a) => Semigroup (Choice 'AtleastOne a)
where Choice x xs <> Choice y ys = Choice (x <> y) (xs <> ys)
instance (Semigroup a, Ord a) => Semigroup (Choice 'Many a)
where Choice x xs <> Choice y ys = Choice (x <> y) (xs <> ys)
instance (Semigroup a, Ord a) => Monoid (Choice 'One a) where mempty = noselection (mempty :: Set a)
instance (Semigroup a, Ord a) => Monoid (Choice 'Many a) where mempty = noselection (mempty :: Set a)
instance Compactable (Choice 'One) where
compact (Choice x xs) = Choice (compact x) (compact xs)
separate (Choice x xs) = let (l,r) = separate xs; (l',r') = separate x in (Choice l' l, Choice r' r)
filter p (Choice x xs) = Choice (Control.Compactable.filter p x) $ Set.filter p xs
partition p (Choice x xs) = let (l, r) = Set.partition p xs; (l',r') = Control.Compactable.partition p x in (Choice l' l, Choice r' r)
instance Compactable (Choice 'Many) where
compact (Choice x xs) = Choice (compact x) (compact xs)
separate (Choice x xs) = let (l,r) = separate xs; (l',r') = separate x in (Choice l' l, Choice r' r)
filter p (Choice x xs) = Choice (Control.Compactable.filter p x) $ Set.filter p xs
partition p (Choice x xs) = let (l, r) = Set.partition p xs; (l',r') = Control.Compactable.partition p x in (Choice l' l, Choice r' r)
class SetLike f where
toSet :: Ord a => f a -> Set a
smap :: Ord b => (a -> b) -> f a -> f b
valid :: Ord a => f a -> Bool
instance SetLike Set where
toSet = id
{-# INLINE toSet #-}
smap = Set.map
{-# INLINE smap #-}
valid = Set.valid
instance SetLike Maybe where
toSet = maybe mempty Set.singleton
{-# INLINE toSet #-}
smap = fmap
{-# INLINE smap #-}
valid = const True
instance SetLike (Choice 'One) where
toSet (Choice x xs) = toSet x <> xs
smap f (Choice x xs) = Choice (f <$> x) (Set.map f xs)
valid (Choice _ xs) = Set.valid xs
instance SetLike (Choice 'AtleastOne) where
toSet (Choice x xs) = Set.singleton x <> xs
smap f (Choice x xs) = Choice (f x) (Set.map f xs)
valid (Choice _ xs) = Set.valid xs
instance SetLike (Choice 'Many) where
toSet (Choice x xs) = toSet x <> xs
smap f (Choice x xs) = Choice (Set.map f x) (Set.map f xs)
valid (Choice x xs) = Set.valid x && Set.valid xs
#ifdef TESTING
class
( forall v. Eq v => Eq (f v)
, forall w. Show w => Show (f w)
, forall x. Ord x => Ord (f x)
, forall y. (Ord y, Semigroup y) => Semigroup (f y)
, forall z. (Ord z, Arbitrary z) => Arbitrary (f z)
) => Propable1Set f
instance
( forall v. Eq v => Eq (f v)
, forall w. Show w => Show (f w)
, forall x. Ord x => Ord (f x)
, forall y. (Ord y, Semigroup y) => Semigroup (f y)
, forall z. (Ord z, Arbitrary z) => Arbitrary (f z)
) => Propable1Set f
type instance Justice SetLike f = Propable1Set f
instance Legal SetLike where legal' _ = setLikeLaws
newtype ApplyOrd f a = ApplyOrd { unApplyOrd :: f a }
deriving instance (forall x. Eq x => Eq (f x), Eq a) => Eq (ApplyOrd f a)
deriving instance (forall x. Show x => Show (f x), Show a) => Show (ApplyOrd f a)
deriving newtype instance
( forall x. (Ord x, Arbitrary x) => Arbitrary (f x)
, Ord a
, Arbitrary a
) => Arbitrary (ApplyOrd f a)
setLikeLaws ::
( SetLike f
, forall c. Eq c => Eq (f c)
, forall d. Show d => Show (f d)
, forall e. (Arbitrary e, Ord e) => Arbitrary (f e)
) => proxy f -> Laws
setLikeLaws p = Laws "SetLike"
[ ("Composition", setFunctorComposition p)
, ("Identity", setFunctorIdentity p)
, ("Const", setFunctorConst p)
]
setFunctorComposition, setFunctorIdentity, setFunctorConst :: forall proxy f.
( SetLike f
, forall a. Eq a => Eq (f a)
, forall a. Show a => Show (f a)
, forall a. (Arbitrary a, Ord a) => Arbitrary (f a)
) => proxy f -> Property
setFunctorComposition _ = property $ \(ApplyOrd (a :: f Integer)) ->
eq1 (smap func2 (smap func1 a)) (smap (func2 . func1) a)
setFunctorIdentity _ = property $ \(ApplyOrd (a :: f Integer)) ->
eq1 (smap id a) a
setFunctorConst _ = property $ \(ApplyOrd (a :: f Integer)) ->
let (<$$) = smap . const in
eq1 (smap (const 'X') a) ('X' <$$ a)
class
( Propable1Ord (f p)
, Propable0 (Selected p Integer)
, DemotePick p, PickToSet p
, Selection f p
) => PropableChoice f p
instance
( Propable1Ord (f p)
, Propable0 (Selected p Integer)
, DemotePick p, PickToSet p
, Selection f p
) => PropableChoice f p
type instance Justice (Selection f) p = PropableChoice f p
instance Legal (Selection f) where
legal' (_ :: Proxy (Selection f)) (_ :: Proxy p) =
let Laws _ laws = selectionLaws (Proxy @(f p))
in Laws ("Selection '" <> show (demotePick @p)) laws
selectionLaws :: forall proxy f (p :: Pick).
( Selection f p
, PickToSet p
, Propable1Ord (f p)
, Propable0 (Selected p Integer)
) => proxy (f p) -> Laws
selectionLaws p = Laws "Selection"
[ ("Selected is an option", selectionIsAnOption p)
, ("Selected and unselected are exclusive", selectedAndUnselectedAreExclusive p)
, ("If we select something it's an option", selectIsAnOption p)
, ("Idempotence select", selectIdempotence p)
, ("Select selected identity", selectSelectedIdentity p)
, ("Unselected withOptions identity", unSelectedWithOptionsIdentity p)
, ("Selected is not unselected", selectIsNotUnselected p)
, ("Retain preserves as much user selection as possible", retainPreserves p)
, ("Retain sets the values", retainSets p)
]
selectionIsAnOption, selectedAndUnselectedAreExclusive
:: forall proxy f (p :: Pick).
( Selection f p
, PickToSet p
, Propable1Ord (f p)
) => proxy (f p) -> Property
selectionIsAnOption _ = property $ \(c :: f p Integer) ->
pickToSet @p (selected c) `isSubsetOf` toSet c
selectedAndUnselectedAreExclusive _ = property $ \(c :: f p Integer) ->
pickToSet @p (selected c) `disjoint` unselected c
selectIsAnOption, selectIdempotence, selectIsNotUnselected
:: forall proxy f (p :: Pick).
( Selection f p
, Propable1Ord (f p)
) => proxy (f p) -> Property
selectIsAnOption _ = property $ \(c :: f p Integer) x ->
x `member` toSet (select' c x)
selectIdempotence _ = property $ \(c :: f p Integer) x ->
select' (select' c x) x == select' c x
selectIsNotUnselected _ = property $ \(c :: f p Integer) x ->
not $ x `member` unselected (select' c x)
selectSelectedIdentity, unSelectedWithOptionsIdentity
:: forall proxy f (p :: Pick).
( Selection f p
, Propable0 (Selected p Integer)
) => proxy (f p) -> Property
selectSelectedIdentity _ = property $ \x ->
selected (x `withOptions` Set.empty :: f p Integer) == x
unSelectedWithOptionsIdentity _ = property $ \x ->
unselected (x `withOptions` Set.empty :: f p Integer ) == mempty
retainPreserves
:: forall proxy f (p :: Pick).
( Selection f p
, PickToSet p
) => proxy (f p) -> Property
retainPreserves _ = property $ \(xs' :: Set Integer) x' y' ->
let x, y :: Selected p Integer
x = pickToSelected @p x'
y = pickToSelected @p y'
xs :: Set Integer
xs = Set.insert x' $ Set.insert y' xs'
r :: f p Integer
r = (x `withOptions` xs) `retain` (y `withOptions` xs)
in pickToSet @p x `isSubsetOf` pickToSet @p @Integer (selected r)
retainSets
:: forall proxy f (p :: Pick).
( Selection f p
, Propable1Ord (f p)
) => proxy (f p) -> Property
retainSets _ = property $ \(c :: f p Integer) x ->
toSet (retain c x) == toSet x
#endif
ftoSet :: (Ord a, Foldable g) => g a -> Set a
ftoSet = Set.fromList . F.toList
class PickToSet (p :: Pick) where pickToSet :: Ord a => Selected p a -> Set a
instance PickToSet 'One where pickToSet = toSet
instance PickToSet 'AtleastOne where pickToSet = Set.singleton
instance PickToSet 'Many where pickToSet = toSet
class PickToSelected (p :: Pick) where pickToSelected' :: Ord a => Proxy p -> a -> Selected p a
instance PickToSelected 'One where pickToSelected' _ = Just
instance PickToSelected 'AtleastOne where pickToSelected' _ = id
instance PickToSelected 'Many where pickToSelected' _ = Set.singleton
pickToSelected :: forall (p :: Pick) a. (Ord a, PickToSelected p) => a -> Selected p a
pickToSelected = pickToSelected' (Proxy @p)
class (SetLike (f p), PickToSelected p) => Selection f (p :: Pick) where
select :: Ord a => f p a -> Selected p a -> f p a
unselected :: Ord a => f p a -> Set a
selected :: Ord a => f p a -> Selected p a
withOptions :: (Foldable g, Ord a) => Selected p a -> g a -> f p a
retain :: Ord a => f p a -> f p a -> f p a
select' :: forall f (p :: Pick) a. (Selection f p, Ord a) => f p a -> a -> f p a
select' c = select c . pickToSelected @p
withOptions' :: forall f (p :: Pick) a g. (Selection f p, Ord a, Foldable g) => a -> g a -> f p a
withOptions' = withOptions . pickToSelected @p
retain' :: (Ord a, Deselection f p, Foldable g) => f p a -> g a -> f p a
retain' xs = retain xs . noselection
instance Selection Choice 'One where
select (Choice w xs) y = Choice y (toSet w <> toSet y <> xs)
unselected (Choice x xs) = maybe xs (`Set.delete` xs) x
selected = _selected
withOptions x (ftoSet -> xs) = Choice x $ maybe xs (`Set.insert` xs) x
retain (Choice w _) xs = case w of
Just x | Set.member x (toSet xs) -> w `withOptions` xs; _ -> xs
instance Selection Choice 'AtleastOne where
select (Choice _ xs) y = Choice y (Set.insert y xs)
unselected (Choice x xs) = Set.delete x xs
selected = _selected
withOptions x (ftoSet -> xs) = Choice x (Set.insert x xs)
retain (Choice w _) xs = if Set.member w (toSet xs) then w `withOptions` xs else xs
instance Selection Choice 'Many where
select (Choice x xs) y = Choice (y <> x) (y <> xs)
unselected (Choice x xs) = Set.difference xs x
selected = _selected
withOptions x (ftoSet -> xs) = Choice x (x <> xs)
retain (Choice x _) (Choice y ys) = Choice (Set.intersection x ys <> y) ys
type family ToS (p :: Pick) :: Type -> Type where
ToS 'One = Maybe
ToS 'Many = Set
class Selection f p => Deselection f (p :: Pick) where
noselection :: (Foldable g, Ord a) => g a -> f p a
deselect :: Ord a => f p a -> f p a
instance Deselection Choice 'One where
noselection = Choice Nothing . Set.fromList . F.toList
deselect = flip select Nothing
instance Deselection Choice 'Many where
noselection = Choice mempty . Set.fromList . F.toList
deselect (Choice ys xs) = Choice mempty (ys <> xs)
#ifdef TESTING
class
( Propable1Ord (f p)
, Propable0 (Selected p (Sum Int))
, Monoid (Selected p (Sum Int))
, DemotePick p, PickToSet p
, Selected p (Sum Int) ~ ToS p (Sum Int)
, SetLike (ToS p)
, Selection f p
) => PropableChoiceDe f p
instance
( Propable1Ord (f p)
, Propable0 (Selected p (Sum Int))
, Monoid (Selected p (Sum Int))
, DemotePick p, PickToSet p
, Selected p (Sum Int) ~ ToS p (Sum Int)
, SetLike (ToS p)
, Selection f p
) => PropableChoiceDe f p
type instance Justice (Deselection f) p = PropableChoiceDe f p
instance Legal (Deselection f) where
legal' (_ :: Proxy (Deselection f)) (_ :: Proxy p) =
deselectionLaws (Proxy @(f p))
deselectionLaws :: forall proxy f (p :: Pick).
( Deselection f p
, Propable1Ord (f p)
, Propable0 (Selected p (Sum Int))
, Monoid (Selected p (Sum Int))
, Selected p (Sum Int) ~ ToS p (Sum Int)
, SetLike (ToS p)
, DemotePick p
) => proxy (f p) -> Laws
deselectionLaws p = Laws ("Deselection '" <> show (demotePick @p))
[ ("idempotence deselect", idempotenceSelect p)
, ("deselect select selected identity", dselectSelectSelectedIdentity p)
, ("selected deselect annihliation", selectedDeselectAnnihliation p)
, ("deselect keeps", deselectKeeps p)
, ("unselected passes through deselect keeps", unselectedPasses p)
, ("deselect unselected is full set", deselectFullSet p)
]
idempotenceSelect, deselectFullSet
:: forall proxy f (p :: Pick).
( Deselection f p
, Propable1Ord (f p)
) => proxy (f p) -> Property
idempotenceSelect _ = property $ \(c :: f p (Sum Int)) ->
deselect (deselect c) == deselect c
deselectFullSet _ = property $ \(c :: f p (Sum Int)) ->
unselected (deselect c) == toSet c
dselectSelectSelectedIdentity
:: forall proxy f (p :: Pick).
( Deselection f p
, Propable1Ord (f p)
, Propable0 (Selected p (Sum Int))
) => proxy (f p) -> Property
dselectSelectSelectedIdentity _ = property $ \(c :: f p (Sum Int)) x ->
selected (select (deselect c) x) == x
selectedDeselectAnnihliation
:: forall proxy f (p :: Pick).
( Deselection f p
, Propable1Ord (f p)
, Propable0 (Selected p (Sum Int))
, Monoid (Selected p (Sum Int))
) => proxy (f p) -> Property
selectedDeselectAnnihliation _ = property $ \(c :: f p (Sum Int)) ->
selected (deselect c) == mempty
deselectKeeps
:: forall proxy f (p :: Pick).
( Deselection f p
, Propable1Ord (f p)
, Propable0 (Selected p (Sum Int))
, Selected p (Sum Int) ~ ToS p (Sum Int)
, SetLike (ToS p)
) => proxy (f p) -> Property
deselectKeeps _ = property $ \(c :: f p (Sum Int)) (x :: Selected p (Sum Int)) ->
toSet (x :: ToS p (Sum Int)) `isSubsetOf` toSet (deselect (select c x))
unselectedPasses
:: forall proxy f (p :: Pick).
( Deselection f p
, Propable1Ord (f p)
, Propable0 (Selected p (Sum Int))
, Selected p (Sum Int) ~ ToS p (Sum Int)
, SetLike (ToS p)
) => proxy (f p) -> Property
unselectedPasses _ = property $ \(c :: f p (Sum Int)) (x :: Selected p (Sum Int)) ->
toSet x `isSubsetOf` unselected (deselect (select c x))
#endif
next, nextLoop, prev, prevLoop :: (Selection f 'AtleastOne, Ord a) => f 'AtleastOne a -> f 'AtleastOne a
next xs = maybe xs (select xs) . Set.lookupGT (selected xs) $ toSet xs
nextLoop xs = maybe (unsafeSelectFirst xs) (select xs) . Set.lookupGT (selected xs) $ toSet xs
prev xs = maybe xs (select xs) . Set.lookupLT (selected xs) $ toSet xs
prevLoop xs = maybe (unsafeSelectLast xs) (select xs) . Set.lookupLT (selected xs) $ toSet xs
selectAll :: Choice 'Many a -> Choice 'Many a
selectAll (Choice _ xs) = Choice xs xs
unsafeSelectFirst :: (Selection f p, Ord a) => f p a -> f p a
unsafeSelectFirst c = select' c . Set.findMin $ toSet c
unsafeSelectLast :: (Selection f p, Ord a) => f p a -> f p a
unsafeSelectLast c = select' c . Set.findMax $ toSet c
selectFirst :: (Selection f p, Ord a) => f p a -> Maybe (f p a)
selectFirst c = fmap (select' c) . Set.lookupMin $ toSet c
selectLast :: (Selection f p, Ord a) => f p a -> Maybe (f p a)
selectLast c = fmap (select' c) . Set.lookupMax $ toSet c
fullset :: (Bounded a, Enum a) => Set a
fullset = Set.fromDistinctAscList [minBound..maxBound]
fullOptions :: (Deselection f p, Bounded a, Enum a, Ord a) => f p a
fullOptions = noselection fullset
fullOptionsMin :: (Selection f p, Bounded a, Enum a, Ord a) => f p a
fullOptionsMin = fromNonEmpty $ minBound NE.:| [succ minBound..maxBound]
fullOptionsMax :: (Selection f p, Bounded a, Enum a, Ord a) => f p a
fullOptionsMax = fromNonEmpty $ maxBound NE.:| [minBound..pred maxBound]
fromNonEmpty :: (Selection f p, Ord a) => NE.NonEmpty a -> f p a
fromNonEmpty xs' = let (x NE.:| xs) = NE.sort xs' in x `withOptions'` Set.fromList xs
selectWhen :: (SetLike g, Selection f 'Many, Ord a) => (a -> Bool) -> g a -> Maybe (f 'Many a)
selectWhen p xs' = if sub == Set.empty then Nothing else Just (sub `withOptions` xs)
where sub = Set.filter p xs
xs = toSet xs'
selectFirstWhen :: (SetLike g, Deselection f p, Ord a) => (a -> Bool) -> g a -> Maybe (f p a)
selectFirstWhen p xs = if sub == Set.empty then Nothing else selectFirst $ noselection sub
where sub = Set.filter p $ toSet xs
selectLastWhen :: (SetLike g, Deselection f p, Ord a) => (a -> Bool) -> g a -> Maybe (f p a)
selectLastWhen p xs = if sub == Set.empty then Nothing else selectLast $ noselection sub
where sub = Set.filter p $ toSet xs
toList :: (SetLike f, Ord a) => f a -> [a]
toList = Set.toList . toSet
singleton :: (Selection f p, Ord a) => a -> f p a
singleton x = x `withOptions'` Set.singleton x
before :: (Selection f 'AtleastOne, Ord a) => f 'AtleastOne a -> Set a
before xs = Set.filter (< selected xs) $ toSet xs
unsafeSelectAt :: (SetLike g, Selection f 'AtleastOne, Ord a) => Int -> g a -> f 'AtleastOne a
unsafeSelectAt i xs' = let xs = toSet xs' in Set.elemAt i xs `withOptions'` xs
getIndex :: (Selection f 'AtleastOne, Ord a) => f 'AtleastOne a -> Int
getIndex xs = findIndex (selected xs) $ toSet xs
after :: (Selection f 'AtleastOne, Ord a) => f 'AtleastOne a -> Set a
after xs = Set.filter (> selected xs) $ toSet xs
size :: (SetLike g, Ord a) => g a -> Int
size = Set.size . toSet
insert :: (Selection f p, Ord a) => a -> f p a -> f p a
insert y xs = selected xs `withOptions` Set.insert y (toSet xs)
delete :: (Compactable (f p), Ord a) => a -> f p a -> f p a
delete y = Control.Compactable.filter (/= y)
addSelection :: (Selection f 'Many, Ord a) => a -> f 'Many a -> f 'Many a
addSelection y c = select c $ Set.singleton y
deselectMany :: (Compactable (f p), Ord a) => Set a -> f p a -> f p a
deselectMany y = Control.Compactable.filter (`Set.member` y)
#ifdef TESTING
instance (Ord a, Arbitrary a, Arbitrary (Selected p a)) => Arbitrary (Choice p a) where
arbitrary = Choice <$> arbitrary <*> arbitrary
#endif