packages feed

mini-2.0.0.0: src/Mini/Data/Set.hs

-- | A structure containing unique elements
module Mini.Data.Set (
  -- * Type
  Set,
  set,

  -- * Construction
  fromList,
  singleton,

  -- * Combination
  difference,
  intersection,
  union,

  -- * Conversion
  toAscList,
  toDescList,

  -- * Max/Min
  deleteMax,
  deleteMin,
  lookupMax,
  lookupMin,
  splitMax,
  splitMin,

  -- * Modification
  delete,
  filter,
  insert,

  -- * Partition
  partition,
  split,

  -- * Query
  disjoint,
  lookupGE,
  lookupGT,
  lookupLE,
  lookupLT,
  member,
  subset,
) where

import Control.Applicative (
  (<|>),
 )
import Data.Bifunctor (
  first,
  second,
 )
import Data.Bool (
  bool,
 )
import Data.Function (
  on,
 )
import Mini.Data.Recursion (
  ordering,
 )
import Mini.Hash.Class (
  Hashable,
  toBytes,
 )
import Prelude (
  Bool (
    False,
    True
  ),
  Eq,
  Foldable,
  Maybe (
    Just,
    Nothing
  ),
  Monoid,
  Ord,
  Semigroup,
  Show,
  all,
  any,
  compare,
  concatMap,
  error,
  flip,
  foldl,
  foldr,
  maximum,
  maybe,
  mempty,
  minimum,
  not,
  null,
  show,
  uncurry,
  ($),
  (.),
  (<$>),
  (<*>),
  (<>),
  (==),
 )

-- Type

-- | A set containing elements of type /a/, internally structured as an AVL tree
data Set a
  = -- | Empty node
    E
  | -- | Left-heavy node
    L (Set a) a (Set a)
  | -- | Balanced node
    B (Set a) a (Set a)
  | -- | Right-heavy node
    R (Set a) a (Set a)

instance (Eq a) => Eq (Set a) where
  (==) = (==) `on` toAscList

instance (Ord a) => Ord (Set a) where
  compare = compare `on` toAscList

instance (Show a) => Show (Set a) where
  show = show . toAscList

instance Foldable Set where
  foldr f b = set' b go go go
   where
    go l a _ _ recr = foldr f (f a recr) l
  null = set' True go go go where go _ _ _ _ _ = False
  maximum = set' (error "maximum: empty set") go go go
   where
    go _ a r _ recr = set' a go' go' go' r
     where
      go' _ _ _ _ _ = recr
  minimum = set' (error "minimum: empty set") go go go
   where
    go l a _ recl _ = set' a go' go' go' l
     where
      go' _ _ _ _ _ = recl

instance (Ord a) => Semigroup (Set a) where
  (<>) = union

instance (Ord a) => Monoid (Set a) where
  mempty = E

instance (Hashable a) => Hashable (Set a) where
  toBytes = concatMap toBytes

-- | Primitive recursion on sets (internally structured as trees)
set
  :: b
  -- ^ Value in case of empty node
  -> (Set a -> a -> Set a -> b -> b -> b)
  -- ^ Function applied in case of non-empty node:
  -- left child, element, right child, left recursion, right recursion
  -- (elements are lesser to the left, greater to the right)
  -> Set a
  -- ^ Object of the case analysis
  -> b
set e f = set' e f f f

-- Primitive recursion on sets
set'
  :: b
  -- ^ Value in case of empty node
  -> (Set a -> a -> Set a -> b -> b -> b)
  -- ^ Function applied in case of left-heavy node:
  -- left child, element, right child, left recursion, right recursion
  -- (elements are lesser to the left, greater to the right)
  -> (Set a -> a -> Set a -> b -> b -> b)
  -- ^ Function applied in case of balanced node:
  -- left child, element, right child, left recursion, right recursion
  -- (elements are lesser to the left, greater to the right)
  -> (Set a -> a -> Set a -> b -> b -> b)
  -- ^ Function applied in case of right-heavy node:
  -- left child, element, right child, left recursion, right recursion
  -- (elements are lesser to the left, greater to the right)
  -> Set a
  -- ^ Object of the case analysis
  -> b
set' e f g h obj = case obj of
  L l a r -> f l a r (set' e f g h l) (set' e f g h r)
  R l a r -> h l a r (set' e f g h l) (set' e f g h r)
  B l a r -> g l a r (set' e f g h l) (set' e f g h r)
  E -> e

-- Construction

-- | /O(n log n)/ Make a set from a list of elements
fromList :: (Ord a) => [a] -> Set a
fromList = foldl (flip insert) mempty

-- | /O(1)/ Make a set with a single element
singleton :: (Ord a) => a -> Set a
singleton a = B mempty a mempty

-- Combination

-- | /O(m log n)/ Subtract a set by another
difference :: (Ord a) => Set a -> Set a -> Set a
difference t1 t2 = set' mempty go go go t1
 where
  go _ _ _ _ _ = foldr (\a b -> bool b (delete a b) $ a `member` b) t1 t2

-- | /O(m log n)/ Intersect a set with another
intersection :: (Ord a) => Set a -> Set a -> Set a
intersection t1 t2 = set' mempty go go go t2
 where
  go _ _ _ _ _ = foldr (\a b -> bool b (insert a b) $ a `member` t2) mempty t1

-- | /O(m log n)/ Unite a set with another
union :: (Ord a) => Set a -> Set a -> Set a
union t1 t2 = set' t2 go go go t1
 where
  go _ _ _ _ _ = foldr (\a b -> bool (insert a b) b $ a `member` b) t1 t2

-- Conversion

-- | /O(n)/ Turn a set into a list of elements in ascending order
toAscList :: Set a -> [a]
toAscList = foldr (:) []

-- | /O(n)/ Turn a set into a list of elements in descending order
toDescList :: Set a -> [a]
toDescList = foldl (flip (:)) []

-- Max/Min

-- | /O(log n)/ Delete the maximum element from a set
deleteMax :: (Ord a) => Set a -> Set a
deleteMax t = maybe t (`delete` t) $ lookupMax t

-- | /O(log n)/ Delete the minimum element from a set
deleteMin :: (Ord a) => Set a -> Set a
deleteMin t = maybe t (`delete` t) $ lookupMin t

-- | /O(log n)/ Fetch the maximum element
lookupMax :: Set a -> Maybe a
lookupMax = set' Nothing go go go
 where
  go _ a r _ recr = set' (Just a) go' go' go' r
   where
    go' _ _ _ _ _ = recr

-- | /O(log n)/ Fetch the minimum element
lookupMin :: Set a -> Maybe a
lookupMin = set' Nothing go go go
 where
  go l a _ recl _ = set' (Just a) go' go' go' l
   where
    go' _ _ _ _ _ = recl

-- | /O(log n)/ Split a set by its maximum element
splitMax :: (Ord a) => Set a -> Maybe (a, Set a)
splitMax t = ((,) <*> flip delete t) <$> lookupMax t

-- | /O(log n)/ Split a set by its minimum element
splitMin :: (Ord a) => Set a -> Maybe (a, Set a)
splitMin t = ((,) <*> flip delete t) <$> lookupMin t

-- Modification

-- | /O(n log n)/ Keep the elements satisfying a predicate
filter :: (Ord a) => (a -> Bool) -> Set a -> Set a
filter p = foldr (\a b -> bool b (insert a b) $ p a) mempty

-- Partition

-- | /O(n log n)/ Partition a set with a predicate into @(true, false)@ subsets
partition :: (Ord a) => (a -> Bool) -> Set a -> (Set a, Set a)
partition p = foldr (\a -> bool second first (p a) (insert a)) (mempty, mempty)

-- | /O(n log n)/ Split a set by an element into @(lt, eq, gt)@ subsets
split :: (Ord a) => a -> Set a -> (Set a, Bool, Set a)
split a0 =
  foldr
    ( \a (lt, a', gt) ->
        ordering
          (insert a lt, a', gt)
          (lt, True, gt)
          (lt, a', insert a gt)
          $ compare a a0
    )
    (mempty, False, mempty)

-- Query

-- | /O(m log n)/ Check whether two sets have no elements in common
disjoint :: (Ord a) => Set a -> Set a -> Bool
disjoint t1 t2 = set' True go go go t1
 where
  go _ _ _ _ _ = not $ any (`member` t1) t2

-- | /O(log n)/ Fetch the least element greater than or equal to the given one
lookupGE :: (Ord a) => a -> Set a -> Maybe a
lookupGE a0 = set' Nothing go go go
 where
  go _ a _ recl recr = ordering recr (Just a) (recl <|> Just a) $ compare a a0

-- | /O(log n)/ Fetch the least element strictly greater than the given one
lookupGT :: (Ord a) => a -> Set a -> Maybe a
lookupGT a0 = set' Nothing go go go
 where
  go _ a _ recl recr = ordering recr recr (recl <|> Just a) $ compare a a0

-- | /O(log n)/ Fetch the greatest element less than or equal to the given one
lookupLE :: (Ord a) => a -> Set a -> Maybe a
lookupLE a0 = set' Nothing go go go
 where
  go _ a _ recl recr = ordering (recr <|> Just a) (Just a) recl $ compare a a0

-- | /O(log n)/ Fetch the greatest element strictly less than the given one
lookupLT :: (Ord a) => a -> Set a -> Maybe a
lookupLT a0 = set' Nothing go go go
 where
  go _ a _ recl recr = ordering (recr <|> Just a) recl recl $ compare a a0

-- | /O(log n)/ Check whether an element is in a set
member :: (Ord a) => a -> Set a -> Bool
member a0 = set' False go go go
 where
  go _ a _ recl recr = ordering recl True recr $ compare a0 a

-- | /O(n log m)/ Check whether the elements of a set exist in the other
subset :: (Ord a) => Set a -> Set a -> Bool
subset t1 t2 = set' (null t1) go go go t2
 where
  go _ _ _ _ _ = all (`member` t2) t1

{-
 - Let this comment serve as your warning. Return from whence you came and your
 - sanity will be spared. You have been admonished.
 -}

-- | /O(log n)/ Delete an element from a set without checking for membership
delete :: (Ord a) => a -> Set a -> Set a
delete a0 =
  set'
    (error "Set.delete: L0")
    ( \l a r _ _ ->
        ordering
          (deleteLl l a r)
          (substituteL l r)
          (deleteLr l a r)
          $ compare a0 a
    )
    ( \l a r _ _ ->
        ordering
          (deleteBl l a r)
          (substituteBr l r)
          (deleteBr l a r)
          $ compare a0 a
    )
    ( \l a r _ _ ->
        ordering
          (deleteRl l a r)
          (substituteR l r)
          (deleteRr l a r)
          $ compare a0 a
    )
 where
  deleteRl l a r =
    set'
      (error "Set.delete: L1")
      ( \ll la lr _ _ ->
          ordering
            (checkLeftR (deleteLl ll la lr) a r)
            (checkLeftR (substituteL ll lr) a r)
            (checkLeftR (deleteLr ll la lr) a r)
            $ compare a0 la
      )
      ( \ll la lr _ _ ->
          ordering
            (R (deleteBl ll la lr) a r)
            (checkLeftR' (substituteBr ll lr) a r)
            (R (deleteBr ll la lr) a r)
            $ compare a0 la
      )
      ( \ll la lr _ _ ->
          ordering
            (checkLeftR (deleteRl ll la lr) a r)
            (checkLeftR (substituteR ll lr) a r)
            (checkLeftR (deleteRr ll la lr) a r)
            $ compare a0 la
      )
      l
  deleteRr l a =
    set'
      (error "Set.delete: L2")
      ( \rl ra rr _ _ ->
          ordering
            (checkRightR l a $ deleteLl rl ra rr)
            (checkRightR l a $ substituteL rl rr)
            (checkRightR l a $ deleteLr rl ra rr)
            $ compare a0 ra
      )
      ( \rl ra rr _ _ ->
          ordering
            (R l a $ deleteBl rl ra rr)
            (checkRightR' l a $ substituteBl rl rr)
            (R l a $ deleteBr rl ra rr)
            $ compare a0 ra
      )
      ( \rl ra rr _ _ ->
          ordering
            (checkRightR l a $ deleteRl rl ra rr)
            (checkRightR l a $ substituteR rl rr)
            (checkRightR l a $ deleteRr rl ra rr)
            $ compare a0 ra
      )
  deleteBl l a r =
    set'
      (error "Set.delete: L3")
      ( \ll la lr _ _ ->
          ordering
            (checkLeftB (deleteLl ll la lr) a r)
            (checkLeftB (substituteL ll lr) a r)
            (checkLeftB (deleteLr ll la lr) a r)
            $ compare a0 la
      )
      ( \ll la lr _ _ ->
          ordering
            (B (deleteBl ll la lr) a r)
            (checkLeftB' (substituteBr ll lr) a r)
            (B (deleteBr ll la lr) a r)
            $ compare a0 la
      )
      ( \ll la lr _ _ ->
          ordering
            (checkLeftB (deleteRl ll la lr) a r)
            (checkLeftB (substituteR ll lr) a r)
            (checkLeftB (deleteRr ll la lr) a r)
            $ compare a0 la
      )
      l
  deleteBr l a =
    set'
      (error "Set.delete: L4")
      ( \rl ra rr _ _ ->
          ordering
            (checkRightB l a $ deleteLl rl ra rr)
            (checkRightB l a $ substituteL rl rr)
            (checkRightB l a $ deleteLr rl ra rr)
            $ compare a0 ra
      )
      ( \rl ra rr _ _ ->
          ordering
            (B l a $ deleteBl rl ra rr)
            (checkRightB' l a $ substituteBl rl rr)
            (B l a $ deleteBr rl ra rr)
            $ compare a0 ra
      )
      ( \rl ra rr _ _ ->
          ordering
            (checkRightB l a $ deleteRl rl ra rr)
            (checkRightB l a $ substituteR rl rr)
            (checkRightB l a $ deleteRr rl ra rr)
            $ compare a0 ra
      )
  deleteLl l a r =
    set'
      (error "Set.delete: L5")
      ( \ll la lr _ _ ->
          ordering
            (checkLeftL (deleteLl ll la lr) a r)
            (checkLeftL (substituteL ll lr) a r)
            (checkLeftL (deleteLr ll la lr) a r)
            $ compare a0 la
      )
      ( \ll la lr _ _ ->
          ordering
            (L (deleteBl ll la lr) a r)
            (checkLeftL' (substituteBr ll lr) a r)
            (L (deleteBr ll la lr) a r)
            $ compare a0 la
      )
      ( \ll la lr _ _ ->
          ordering
            (checkLeftL (deleteRl ll la lr) a r)
            (checkLeftL (substituteR ll lr) a r)
            (checkLeftL (deleteRr ll la lr) a r)
            $ compare a0 la
      )
      l
  deleteLr l a =
    set'
      (error "Set.delete: L6")
      ( \rl ra rr _ _ ->
          ordering
            (checkRightL l a $ deleteLl rl ra rr)
            (checkRightL l a $ substituteL rl rr)
            (checkRightL l a $ deleteLr rl ra rr)
            $ compare a0 ra
      )
      ( \rl ra rr _ _ ->
          ordering
            (L l a $ deleteBl rl ra rr)
            (checkRightL' l a $ substituteBl rl rr)
            (L l a $ deleteBr rl ra rr)
            $ compare a0 ra
      )
      ( \rl ra rr _ _ ->
          ordering
            (checkRightL l a $ deleteRl rl ra rr)
            (checkRightL l a $ substituteR rl rr)
            (checkRightL l a $ deleteRr rl ra rr)
            $ compare a0 ra
      )
  rebalanceR l a =
    set'
      (error "Set.delete: L7")
      ( \rl ra rr _ _ ->
          set'
            (error "Set.delete: L8")
            (\rll rla rlr _ _ -> B (B l a rll) rla $ R rlr ra rr)
            (\rll rla rlr _ _ -> B (B l a rll) rla $ B rlr ra rr)
            (\rll rla rlr _ _ -> B (L l a rll) rla $ B rlr ra rr)
            rl
      )
      (\rl ra rr _ _ -> L (R l a rl) ra rr)
      (\rl ra rr _ _ -> B (B l a rl) ra rr)
  rebalanceL l a r =
    set'
      (error "Set.delete: L9")
      (\ll la lr _ _ -> B ll la $ B lr a r)
      (\ll la lr _ _ -> R ll la $ L lr a r)
      ( \ll la lr _ _ ->
          set'
            (error "Set.delete: L10")
            (\lrl lra lrr _ _ -> B (B ll la lrl) lra $ R lrr a r)
            (\lrl lra lrr _ _ -> B (B ll la lrl) lra $ B lrr a r)
            (\lrl lra lrr _ _ -> B (L ll la lrl) lra $ B lrr a r)
            lr
      )
      l
  checkLeftR l a r =
    set'
      (error "Set.delete: L11")
      (\_ _ _ _ _ -> R l a r)
      (\_ _ _ _ _ -> rebalanceR l a r)
      (\_ _ _ _ _ -> R l a r)
      l
  checkLeftB l a r =
    set'
      (error "Set.delete: L12")
      (\_ _ _ _ _ -> B l a r)
      (\_ _ _ _ _ -> R l a r)
      (\_ _ _ _ _ -> B l a r)
      l
  checkLeftL l a r =
    set'
      (error "Set.delete: L13")
      (\_ _ _ _ _ -> L l a r)
      (\_ _ _ _ _ -> B l a r)
      (\_ _ _ _ _ -> L l a r)
      l
  checkRightR l a r =
    set'
      (error "Set.delete: L14")
      (\_ _ _ _ _ -> R l a r)
      (\_ _ _ _ _ -> B l a r)
      (\_ _ _ _ _ -> R l a r)
      r
  checkRightB l a r =
    set'
      (error "Set.delete: L15")
      (\_ _ _ _ _ -> B l a r)
      (\_ _ _ _ _ -> L l a r)
      (\_ _ _ _ _ -> B l a r)
      r
  checkRightL l a r =
    set'
      (error "Set.delete: L16")
      (\_ _ _ _ _ -> L l a r)
      (\_ _ _ _ _ -> rebalanceL l a r)
      (\_ _ _ _ _ -> L l a r)
      r
  substituteR l =
    set'
      (error "Set.delete: L17")
      (\rl ra rr _ _ -> uncurry (checkRightR l) $ popLeftL rl ra rr)
      (\rl ra rr _ _ -> uncurry (checkRightR' l) $ popLeftB rl ra rr)
      (\rl ra rr _ _ -> uncurry (checkRightR l) $ popLeftR rl ra rr)
  substituteBr l =
    set'
      E
      (\rl ra rr _ _ -> uncurry (checkRightB l) $ popLeftL rl ra rr)
      (\rl ra rr _ _ -> uncurry (checkRightB' l) $ popLeftB rl ra rr)
      (\rl ra rr _ _ -> uncurry (checkRightB l) $ popLeftR rl ra rr)
  substituteBl l r =
    set'
      E
      (\ll la lr _ _ -> (\(l', a) -> checkLeftB l' a r) $ popRightL ll la lr)
      (\ll la lr _ _ -> (\(l', a) -> checkLeftB' l' a r) $ popRightB ll la lr)
      (\ll la lr _ _ -> (\(l', a) -> checkLeftB l' a r) $ popRightR ll la lr)
      l
  substituteL l r =
    set'
      (error "Set.delete: L18")
      (\ll la lr _ _ -> (\(l', a) -> checkLeftL l' a r) $ popRightL ll la lr)
      (\ll la lr _ _ -> (\(l', a) -> checkLeftL' l' a r) $ popRightB ll la lr)
      (\ll la lr _ _ -> (\(l', a) -> checkLeftL l' a r) $ popRightR ll la lr)
      l
  checkLeftR' l a r =
    set'
      (rebalanceR l a r)
      (\_ _ _ _ _ -> R l a r)
      (\_ _ _ _ _ -> R l a r)
      (\_ _ _ _ _ -> R l a r)
      l
  checkLeftB' l a r =
    set'
      (R l a r)
      (\_ _ _ _ _ -> B l a r)
      (\_ _ _ _ _ -> B l a r)
      (\_ _ _ _ _ -> B l a r)
      l
  checkLeftL' l a r =
    set'
      (B l a r)
      (\_ _ _ _ _ -> L l a r)
      (\_ _ _ _ _ -> L l a r)
      (\_ _ _ _ _ -> L l a r)
      l
  checkRightR' l a r =
    set'
      (B l a r)
      (\_ _ _ _ _ -> R l a r)
      (\_ _ _ _ _ -> R l a r)
      (\_ _ _ _ _ -> R l a r)
      r
  checkRightB' l a r =
    set'
      (L l a r)
      (\_ _ _ _ _ -> B l a r)
      (\_ _ _ _ _ -> B l a r)
      (\_ _ _ _ _ -> B l a r)
      r
  checkRightL' l a r =
    set'
      (rebalanceL l a r)
      (\_ _ _ _ _ -> L l a r)
      (\_ _ _ _ _ -> L l a r)
      (\_ _ _ _ _ -> L l a r)
      r
  popLeftR l a r =
    set'
      (a, r)
      ( \ll la lr _ _ ->
          (\(a', l') -> (a', checkLeftR l' a r)) $
            popLeftL ll la lr
      )
      (\ll la lr _ _ -> popLeftRB ll la lr a r)
      ( \ll la lr _ _ ->
          (\(a', l') -> (a', checkLeftR l' a r)) $
            popLeftR ll la lr
      )
      l
  popLeftB l a r =
    set'
      (a, E)
      (\ll la lr _ _ -> popLeftBL ll la lr a r)
      (\ll la lr _ _ -> popLeftBB ll la lr a r)
      (\ll la lr _ _ -> popLeftBR ll la lr a r)
      l
  popLeftL l a r =
    set'
      (error "Set.delete: L19")
      ( \ll la lr _ _ ->
          (\(a', l') -> (a', checkLeftL l' a r)) $
            popLeftL ll la lr
      )
      (\ll la lr _ _ -> popLeftLB ll la lr a r)
      ( \ll la lr _ _ ->
          (\(a', l') -> (a', checkLeftL l' a r)) $
            popLeftR ll la lr
      )
      l
  popLeftRB ll la lr a r =
    set'
      (la, rebalanceR E a r)
      ( \lll lla llr _ _ ->
          (\(a', l) -> (a', R l a r)) $
            popLeftBL lll lla llr la lr
      )
      ( \lll lla llr _ _ ->
          (\(a', l) -> (a', R l a r)) $
            popLeftBB lll lla llr la lr
      )
      ( \lll lla llr _ _ ->
          (\(a', l) -> (a', R l a r)) $
            popLeftBR lll lla llr la lr
      )
      ll
  popLeftBB ll la lr a r =
    set'
      (la, R E a r)
      ( \lll lla llr _ _ ->
          (\(a', l) -> (a', B l a r)) $
            popLeftBL lll lla llr la lr
      )
      ( \lll lla llr _ _ ->
          (\(a', l) -> (a', B l a r)) $
            popLeftBB lll lla llr la lr
      )
      ( \lll lla llr _ _ ->
          (\(a', l) -> (a', B l a r)) $
            popLeftBR lll lla llr la lr
      )
      ll
  popLeftLB ll la lr a r =
    set'
      (la, B E a E)
      ( \lll lla llr _ _ ->
          (\(a', l) -> (a', L l a r)) $
            popLeftBL lll lla llr la lr
      )
      ( \lll lla llr _ _ ->
          (\(a', l) -> (a', L l a r)) $
            popLeftBB lll lla llr la lr
      )
      ( \lll lla llr _ _ ->
          (\(a', l) -> (a', L l a r)) $
            popLeftBR lll lla llr la lr
      )
      ll
  popLeftBR ll la lr a r =
    (\(a', l) -> (a', checkLeftB l a r)) $
      popLeftR ll la lr
  popLeftBL ll la lr a r =
    (\(a', l) -> (a', checkLeftB l a r)) $
      popLeftL ll la lr
  popRightR l a =
    set'
      (error "Set.delete: L20")
      (\rl ra rr _ _ -> first (checkRightR l a) $ popRightL rl ra rr)
      (\rl ra rr _ _ -> popRightRB l a rl ra rr)
      (\rl ra rr _ _ -> first (checkRightR l a) $ popRightR rl ra rr)
  popRightB l a =
    set'
      (E, a)
      (\rl ra rr _ _ -> popRightBL l a rl ra rr)
      (\rl ra rr _ _ -> popRightBB l a rl ra rr)
      (\rl ra rr _ _ -> popRightBR l a rl ra rr)
  popRightL l a =
    set'
      (l, a)
      (\rl ra rr _ _ -> first (checkRightL l a) $ popRightL rl ra rr)
      (\rl ra rr _ _ -> popRightLB l a rl ra rr)
      (\rl ra rr _ _ -> first (checkRightL l a) $ popRightR rl ra rr)
  popRightRB l a rl ra =
    set'
      (B E a E, ra)
      (\rrl rra rrr _ _ -> first (R l a) $ popRightBL rl ra rrl rra rrr)
      (\rrl rra rrr _ _ -> first (R l a) $ popRightBB rl ra rrl rra rrr)
      (\rrl rra rrr _ _ -> first (R l a) $ popRightBR rl ra rrl rra rrr)
  popRightBB l a rl ra =
    set'
      (L l a E, ra)
      (\rrl rra rrr _ _ -> first (B l a) $ popRightBL rl ra rrl rra rrr)
      (\rrl rra rrr _ _ -> first (B l a) $ popRightBB rl ra rrl rra rrr)
      (\rrl rra rrr _ _ -> first (B l a) $ popRightBR rl ra rrl rra rrr)
  popRightLB l a rl ra =
    set'
      (rebalanceL l a E, ra)
      (\rrl rra rrr _ _ -> first (L l a) $ popRightBL rl ra rrl rra rrr)
      (\rrl rra rrr _ _ -> first (L l a) $ popRightBB rl ra rrl rra rrr)
      (\rrl rra rrr _ _ -> first (L l a) $ popRightBR rl ra rrl rra rrr)
  popRightBR l a rl ra rr = first (checkRightB l a) $ popRightR rl ra rr
  popRightBL l a rl ra rr = first (checkRightB l a) $ popRightL rl ra rr

-- | /O(log n)/ Insert an element into a set without checking for membership
insert :: (Ord a) => a -> Set a -> Set a
insert a0 =
  set'
    (B E a0 E)
    (\l a r _ _ -> insertL l a r)
    (\l a r _ _ -> insertB l a r)
    (\l a r _ _ -> insertR l a r)
 where
  insertR l a r =
    ordering
      (insertRl l a r)
      (R l a0 r)
      (insertRr l a r)
      $ compare a0 a
  insertB l a r =
    ordering
      (insertBl l a r)
      (B l a0 r)
      (insertBr l a r)
      $ compare a0 a
  insertL l a r =
    ordering
      (insertLl l a r)
      (L l a0 r)
      (insertLr l a r)
      $ compare a0 a
  insertRl l a r =
    set'
      (B (B E a0 E) a r)
      (\ll la lr _ _ -> R (insertL ll la lr) a r)
      ( \ll la lr _ _ ->
          let l' = insertB ll la lr
           in set'
                (error "Set.insert: L0")
                (\_ _ _ _ _ -> B l' a r)
                (\_ _ _ _ _ -> R l' a r)
                (\_ _ _ _ _ -> B l' a r)
                l'
      )
      (\ll la lr _ _ -> R (insertR ll la lr) a r)
      l
  insertBl l a r =
    set'
      (L (B E a0 E) a r)
      (\ll la lr _ _ -> B (insertL ll la lr) a r)
      ( \ll la lr _ _ ->
          let l' = insertB ll la lr
           in set'
                (error "Set.insert: L1")
                (\_ _ _ _ _ -> L l' a r)
                (\_ _ _ _ _ -> B l' a r)
                (\_ _ _ _ _ -> L l' a r)
                l'
      )
      (\ll la lr _ _ -> B (insertR ll la lr) a r)
      l
  insertBr l a =
    set'
      (R l a $ B E a0 E)
      (\rl ra rr _ _ -> B l a $ insertL rl ra rr)
      ( \rl ra rr _ _ ->
          let r = insertB rl ra rr
           in set'
                (error "Set.insert: L2")
                (\_ _ _ _ _ -> R l a r)
                (\_ _ _ _ _ -> B l a r)
                (\_ _ _ _ _ -> R l a r)
                r
      )
      (\rl ra rr _ _ -> B l a $ insertR rl ra rr)
  insertLr l a =
    set'
      (B l a $ B E a0 E)
      (\rl ra rr _ _ -> L l a $ insertL rl ra rr)
      ( \rl ra rr _ _ ->
          let r = insertB rl ra rr
           in set'
                (error "Set.insert: L3")
                (\_ _ _ _ _ -> B l a r)
                (\_ _ _ _ _ -> L l a r)
                (\_ _ _ _ _ -> B l a r)
                r
      )
      (\rl ra rr _ _ -> L l a $ insertR rl ra rr)
  insertRr l a =
    set'
      (error "Set.insert: L4")
      (\rl ra rr _ _ -> R l a $ insertL rl ra rr)
      ( \rl ra rr _ _ ->
          ordering
            (insertRrl l a rl ra rr)
            (R l a $ B rl a0 rr)
            (insertRrr l a rl ra rr)
            $ compare a0 ra
      )
      (\rl ra rr _ _ -> R l a $ insertR rl ra rr)
  insertLl l a r =
    set'
      (error "Set.insert: L5")
      (\ll la lr _ _ -> L (insertL ll la lr) a r)
      ( \ll la lr _ _ ->
          ordering
            (insertLll ll la lr a r)
            (L (B ll a0 lr) a r)
            (insertLlr ll la lr a r)
            $ compare a0 la
      )
      (\ll la lr _ _ -> L (insertR ll la lr) a r)
      l
  insertRrr l a rl ra =
    set'
      (B (B l a rl) ra $ B E a0 E)
      (\rrl rra rrr _ _ -> R l a . B rl ra $ insertL rrl rra rrr)
      ( \rrl rra rrr _ _ ->
          let rr = insertB rrl rra rrr
           in set'
                (error "Set.insert: L6")
                (\_ _ _ _ _ -> B (B l a rl) ra rr)
                (\_ _ _ _ _ -> R l a $ B rl ra rr)
                (\_ _ _ _ _ -> B (B l a rl) ra rr)
                rr
      )
      (\rrl rra rrr _ _ -> R l a . B rl ra $ insertR rrl rra rrr)
  insertLll ll la lr a r =
    set'
      (B (B E a0 E) la $ B lr a r)
      (\lll lla llr _ _ -> L (B (insertL lll lla llr) la lr) a r)
      ( \lll lla llr _ _ ->
          let ll' = insertB lll lla llr
           in set'
                (error "Set.insert: L7")
                (\_ _ _ _ _ -> B ll' la $ B lr a r)
                (\_ _ _ _ _ -> L (B ll' la lr) a r)
                (\_ _ _ _ _ -> B ll' la $ B lr a r)
                ll'
      )
      (\lll lla llr _ _ -> L (B (insertR lll lla llr) la lr) a r)
      ll
  insertRrl l a rl ra rr =
    set'
      (B (B l a E) a0 $ B E ra rr)
      (\rll rla rlr _ _ -> R l a $ B (insertL rll rla rlr) ra rr)
      ( \rll rla rlr _ _ ->
          let rl' = insertB rll rla rlr
           in set'
                (error "Set.insert: L8")
                (\rll' rla' rlr' _ _ -> B (B l a rll') rla' $ R rlr' ra rr)
                (\_ _ _ _ _ -> R l a $ B rl' ra rr)
                (\rll' rla' rlr' _ _ -> B (L l a rll') rla' $ B rlr' ra rr)
                rl'
      )
      (\rll rla rlr _ _ -> R l a $ B (insertR rll rla rlr) ra rr)
      rl
  insertLlr ll la lr a r =
    set'
      (B (B ll la E) a0 $ B E a r)
      (\lrl lra lrr _ _ -> L (B ll la $ insertL lrl lra lrr) a r)
      ( \lrl lra lrr _ _ ->
          let lr' = insertB lrl lra lrr
           in set'
                (error "Set.insert: L9")
                (\lrl' lra' lrr' _ _ -> B (B ll la lrl') lra' $ R lrr' a r)
                (\_ _ _ _ _ -> L (B ll la lr') a r)
                (\lrl' lra' lrr' _ _ -> B (L ll la lrl') lra' $ B lrr' a r)
                lr'
      )
      (\lrl lra lrr _ _ -> L (B ll la $ insertR lrl lra lrr) a r)
      lr