I’m using Data.Sets in deeply-nested heterogeneous data structures, and thought it would be helpful to create a Prism for set membership. Hence:
membership :: (Ord a) => a -> Prism' (Set a) (Set a)
membership a = prism (Set.insert a) g
where g as = if Set.member a as
then Right $ Set.delete a as
else Left as
However, this fails the first prism law, preview l (review l b) ≡ Just b, in the case where review l inserts a member that is already present in b, viz., if l is the membership lens for a, and b is {a}, then review l b is also {a}, and preview l (review l b) is just the null set, rather than just {a} as the first prism law requires.
Is there a better optic for capturing set membership? I like being able to check membership and conditionally decompose the set into the matching and non-matching parts simultaneously. Additionally, having an optic to do this is appealing because, since it captures all the use-cases I have for working with Sets in other parts of my code, it enables me to remove my import Data.Set statements from the rest of my package, which often indicates successful abstraction to me.