{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ViewPatterns #-}

module Data.OSet.Strict (
  OSet (Empty, (:<|:), (:|>:)),
  null,
  size,
  empty,
  singleton,
  lookup,
  member,
  (!?),
  fromList,
  fromStrictSeq,
  fromStrictSeqDuplicates,
  toStrictSeq,
  toSet,
  fromSet,
  fromFoldable,
  fromFoldableDuplicates,
  invariantHolds,
  invariantHolds',
  (|>),
  (<|),
  (|><),
  (><|),
  filter,
)
where

import Cardano.Ledger.Binary (
  DecCBOR (decCBOR),
  EncCBOR (encCBOR),
  decodeSetLikeEnforceNoDuplicates,
  encodeStrictSeq,
  encodeTag,
  setTag,
 )
import Control.DeepSeq (NFData)
import Data.Aeson (ToJSON (toJSON))
import Data.Foldable qualified as F
import Data.Sequence.Strict qualified as SSeq
import Data.Set qualified as Set
import GHC.Exts qualified as GHC (IsList (..))
import GHC.Generics (Generic)
import NoThunks.Class (NoThunks)
import Prelude hiding (filter, lookup, null, seq)

-- | A general-purpose finite, ordered, set that is strict in its
-- values.
--
-- The strictness is enforced by the underlying `StrictSeq` from base,
-- and the uniqueness of the values is enforced in this module, by the
-- constructing functions by leveraging an accompanying `Set`.
--
-- TODO: @aniketd Implement DecShareCBOR
data OSet a = OSet
  { forall a. OSet a -> StrictSeq a
osSSeq :: !(SSeq.StrictSeq a)
  , forall a. OSet a -> Set a
osSet :: !(Set.Set a)
  }
  deriving stock (OSet a -> OSet a -> Bool
forall a. Eq a => OSet a -> OSet a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: OSet a -> OSet a -> Bool
$c/= :: forall a. Eq a => OSet a -> OSet a -> Bool
== :: OSet a -> OSet a -> Bool
$c== :: forall a. Eq a => OSet a -> OSet a -> Bool
Eq, OSet a -> OSet a -> Bool
OSet a -> OSet a -> Ordering
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall {a}. Ord a => Eq (OSet a)
forall a. Ord a => OSet a -> OSet a -> Bool
forall a. Ord a => OSet a -> OSet a -> Ordering
forall a. Ord a => OSet a -> OSet a -> OSet a
min :: OSet a -> OSet a -> OSet a
$cmin :: forall a. Ord a => OSet a -> OSet a -> OSet a
max :: OSet a -> OSet a -> OSet a
$cmax :: forall a. Ord a => OSet a -> OSet a -> OSet a
>= :: OSet a -> OSet a -> Bool
$c>= :: forall a. Ord a => OSet a -> OSet a -> Bool
> :: OSet a -> OSet a -> Bool
$c> :: forall a. Ord a => OSet a -> OSet a -> Bool
<= :: OSet a -> OSet a -> Bool
$c<= :: forall a. Ord a => OSet a -> OSet a -> Bool
< :: OSet a -> OSet a -> Bool
$c< :: forall a. Ord a => OSet a -> OSet a -> Bool
compare :: OSet a -> OSet a -> Ordering
$ccompare :: forall a. Ord a => OSet a -> OSet a -> Ordering
Ord, Int -> OSet a -> ShowS
forall a. Show a => Int -> OSet a -> ShowS
forall a. Show a => [OSet a] -> ShowS
forall a. Show a => OSet a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [OSet a] -> ShowS
$cshowList :: forall a. Show a => [OSet a] -> ShowS
show :: OSet a -> String
$cshow :: forall a. Show a => OSet a -> String
showsPrec :: Int -> OSet a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> OSet a -> ShowS
Show, forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (OSet a) x -> OSet a
forall a x. OSet a -> Rep (OSet a) x
$cto :: forall a x. Rep (OSet a) x -> OSet a
$cfrom :: forall a x. OSet a -> Rep (OSet a) x
Generic)
  deriving (forall a. NoThunks a => Context -> OSet a -> IO (Maybe ThunkInfo)
forall a. NoThunks a => Proxy (OSet a) -> String
forall a.
(Context -> a -> IO (Maybe ThunkInfo))
-> (Context -> a -> IO (Maybe ThunkInfo))
-> (Proxy a -> String)
-> NoThunks a
showTypeOf :: Proxy (OSet a) -> String
$cshowTypeOf :: forall a. NoThunks a => Proxy (OSet a) -> String
wNoThunks :: Context -> OSet a -> IO (Maybe ThunkInfo)
$cwNoThunks :: forall a. NoThunks a => Context -> OSet a -> IO (Maybe ThunkInfo)
noThunks :: Context -> OSet a -> IO (Maybe ThunkInfo)
$cnoThunks :: forall a. NoThunks a => Context -> OSet a -> IO (Maybe ThunkInfo)
NoThunks, forall a. NFData a => OSet a -> ()
forall a. (a -> ()) -> NFData a
rnf :: OSet a -> ()
$crnf :: forall a. NFData a => OSet a -> ()
NFData)

instance Ord a => Semigroup (OSet a) where
  <> :: OSet a -> OSet a -> OSet a
(<>) = forall a. Ord a => OSet a -> OSet a -> OSet a
(|><)

instance Ord a => Monoid (OSet a) where
  mempty :: OSet a
mempty = forall a. OSet a
empty

instance Ord a => GHC.IsList (OSet a) where
  type Item (OSet a) = a
  fromList :: [Item (OSet a)] -> OSet a
fromList = forall a. Ord a => [a] -> OSet a
fromList
  toList :: OSet a -> [Item (OSet a)]
toList = forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. OSet a -> StrictSeq a
osSSeq

instance Foldable OSet where
  foldMap :: forall m a. Monoid m => (a -> m) -> OSet a -> m
foldMap a -> m
f = forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
F.foldMap a -> m
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. StrictSeq a -> Seq a
SSeq.fromStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. OSet a -> StrictSeq a
osSSeq
  {-# INLINEABLE foldMap #-}
  foldr :: forall a b. (a -> b -> b) -> b -> OSet a -> b
foldr a -> b -> b
f b
z = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr a -> b -> b
f b
z forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. StrictSeq a -> Seq a
SSeq.fromStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. OSet a -> StrictSeq a
osSSeq
  {-# INLINEABLE foldr #-}
  foldl :: forall b a. (b -> a -> b) -> b -> OSet a -> b
foldl b -> a -> b
f b
z = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl b -> a -> b
f b
z forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. StrictSeq a -> Seq a
SSeq.fromStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. OSet a -> StrictSeq a
osSSeq
  {-# INLINEABLE foldl #-}
  foldr' :: forall a b. (a -> b -> b) -> b -> OSet a -> b
foldr' a -> b -> b
f b
z = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr' a -> b -> b
f b
z forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. StrictSeq a -> Seq a
SSeq.fromStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. OSet a -> StrictSeq a
osSSeq
  {-# INLINEABLE foldr' #-}
  foldl' :: forall b a. (b -> a -> b) -> b -> OSet a -> b
foldl' b -> a -> b
f b
z = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' b -> a -> b
f b
z forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. StrictSeq a -> Seq a
SSeq.fromStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. OSet a -> StrictSeq a
osSSeq
  {-# INLINEABLE foldl' #-}
  foldr1 :: forall a. (a -> a -> a) -> OSet a -> a
foldr1 a -> a -> a
f = forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
F.foldr1 a -> a -> a
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. StrictSeq a -> Seq a
SSeq.fromStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. OSet a -> StrictSeq a
osSSeq
  {-# INLINEABLE foldr1 #-}
  foldl1 :: forall a. (a -> a -> a) -> OSet a -> a
foldl1 a -> a -> a
f = forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
F.foldl1 a -> a -> a
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. StrictSeq a -> Seq a
SSeq.fromStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. OSet a -> StrictSeq a
osSSeq
  {-# INLINEABLE foldl1 #-}
  length :: forall a. OSet a -> Int
length = forall (t :: * -> *) a. Foldable t => t a -> Int
F.length forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. StrictSeq a -> Seq a
SSeq.fromStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. OSet a -> StrictSeq a
osSSeq
  {-# INLINE length #-}
  null :: forall a. OSet a -> Bool
null = forall (t :: * -> *) a. Foldable t => t a -> Bool
F.null forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. StrictSeq a -> Seq a
SSeq.fromStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. OSet a -> StrictSeq a
osSSeq
  {-# INLINE null #-}

instance EncCBOR a => EncCBOR (OSet a) where
  encCBOR :: OSet a -> Encoding
encCBOR (OSet StrictSeq a
seq Set a
_set) = Word -> Encoding
encodeTag Word
setTag forall a. Semigroup a => a -> a -> a
<> forall a. (a -> Encoding) -> StrictSeq a -> Encoding
encodeStrictSeq forall a. EncCBOR a => a -> Encoding
encCBOR StrictSeq a
seq

instance (Show a, Ord a, DecCBOR a) => DecCBOR (OSet a) where
  decCBOR :: forall s. Decoder s (OSet a)
decCBOR = forall s a b c.
Monoid b =>
(a -> b -> b) -> (b -> (Int, c)) -> Decoder s a -> Decoder s c
decodeSetLikeEnforceNoDuplicates (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. Ord a => OSet a -> a -> OSet a
snoc) (\OSet a
oset -> (forall a. OSet a -> Int
size OSet a
oset, OSet a
oset)) forall a s. DecCBOR a => Decoder s a
decCBOR

instance ToJSON a => ToJSON (OSet a) where
  toJSON :: OSet a -> Value
toJSON = forall a. ToJSON a => a -> Value
toJSON forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList

-- | \( O(1) \). Shallow invariant using just `length` and `size`.
invariantHolds :: OSet a -> Bool
invariantHolds :: forall a. OSet a -> Bool
invariantHolds (OSet StrictSeq a
seq Set a
set) = forall a. StrictSeq a -> Int
SSeq.length StrictSeq a
seq forall a. Eq a => a -> a -> Bool
== forall a. Set a -> Int
Set.size Set a
set

-- | \( O(n \log n) \). Deep invariant using set membership check for
-- each value. By the pigeon-hole principle, this check is exhaustive.
invariantHolds' :: Ord a => OSet a -> Bool
invariantHolds' :: forall a. Ord a => OSet a -> Bool
invariantHolds' oset :: OSet a
oset@(OSet StrictSeq a
seq Set a
set) =
  forall a. OSet a -> Bool
invariantHolds OSet a
oset Bool -> Bool -> Bool
&& forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (forall a. Ord a => a -> Set a -> Bool
`Set.member` Set a
set) (forall a. StrictSeq a -> Seq a
SSeq.fromStrict StrictSeq a
seq)

-- | \( O(1) \).
null :: OSet a -> Bool
null :: forall a. OSet a -> Bool
null (OSet StrictSeq a
_ Set a
set) = forall a. Set a -> Bool
Set.null Set a
set

-- | \( O(1) \).
size :: OSet a -> Int
size :: forall a. OSet a -> Int
size (OSet StrictSeq a
_ Set a
set) = forall a. Set a -> Int
Set.size Set a
set

-- | \( O(1) \).
empty :: OSet a
empty :: forall a. OSet a
empty = forall a. StrictSeq a -> Set a -> OSet a
OSet forall a. StrictSeq a
SSeq.Empty forall a. Set a
Set.empty

-- | \( O(1) \). Strict in its argument.
singleton :: a -> OSet a
singleton :: forall a. a -> OSet a
singleton !a
x = forall a. StrictSeq a -> Set a -> OSet a
OSet (forall a. a -> StrictSeq a
SSeq.singleton a
x) (forall a. a -> Set a
Set.singleton a
x)

-- | \( O(\log(\min(i,n-i))) \). The element at the specified position,
-- counting from 0. If the specified position is negative or at least
-- the length of the sequence, 'lookup' returns 'Nothing'.
lookup :: Int -> OSet a -> Maybe a
lookup :: forall a. Int -> OSet a -> Maybe a
lookup Int
i (OSet StrictSeq a
seq Set a
_set) = forall a. Int -> StrictSeq a -> Maybe a
SSeq.lookup Int
i StrictSeq a
seq

-- | `flip`ed version of `lookup`
(!?) :: OSet a -> Int -> Maybe a
!? :: forall a. OSet a -> Int -> Maybe a
(!?) = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. Int -> OSet a -> Maybe a
lookup

-- | \( O(\log n) \). Checks membership before cons'ing.
cons :: Ord a => a -> OSet a -> OSet a
cons :: forall a. Ord a => a -> OSet a -> OSet a
cons a
x oset :: OSet a
oset@(OSet StrictSeq a
seq Set a
set) =
  if a
x forall a. Ord a => a -> Set a -> Bool
`Set.member` Set a
set
    then OSet a
oset
    else forall a. StrictSeq a -> Set a -> OSet a
OSet (a
x forall a. a -> StrictSeq a -> StrictSeq a
SSeq.<| StrictSeq a
seq) (a
x forall a. Ord a => a -> Set a -> Set a
`Set.insert` Set a
set)

(<|) :: Ord a => a -> OSet a -> OSet a
<| :: forall a. Ord a => a -> OSet a -> OSet a
(<|) = forall a. Ord a => a -> OSet a -> OSet a
cons

infixr 5 <|

-- | \( O(\log n) \). Checks membership before snoc'ing.
snoc :: Ord a => OSet a -> a -> OSet a
snoc :: forall a. Ord a => OSet a -> a -> OSet a
snoc oset :: OSet a
oset@(OSet StrictSeq a
seq Set a
set) a
x =
  if a
x forall a. Ord a => a -> Set a -> Bool
`Set.member` Set a
set
    then OSet a
oset
    else forall a. StrictSeq a -> Set a -> OSet a
OSet (StrictSeq a
seq forall a. StrictSeq a -> a -> StrictSeq a
SSeq.|> a
x) (a
x forall a. Ord a => a -> Set a -> Set a
`Set.insert` Set a
set)

(|>) :: Ord a => OSet a -> a -> OSet a
|> :: forall a. Ord a => OSet a -> a -> OSet a
(|>) = forall a. Ord a => OSet a -> a -> OSet a
snoc

infixl 5 |>

-- | \( O(\log n) \).
uncons :: Ord a => OSet a -> Maybe (a, OSet a)
uncons :: forall a. Ord a => OSet a -> Maybe (a, OSet a)
uncons (OSet StrictSeq a
seq Set a
set) = case StrictSeq a
seq of
  StrictSeq a
SSeq.Empty -> forall a. Maybe a
Nothing
  a
x SSeq.:<| StrictSeq a
xs' -> forall a. a -> Maybe a
Just (a
x, forall a. StrictSeq a -> Set a -> OSet a
OSet StrictSeq a
xs' (a
x forall a. Ord a => a -> Set a -> Set a
`Set.delete` Set a
set))

-- | \( O(\log n) \).
unsnoc :: Ord a => OSet a -> Maybe (OSet a, a)
unsnoc :: forall a. Ord a => OSet a -> Maybe (OSet a, a)
unsnoc (OSet StrictSeq a
seq Set a
set) = case StrictSeq a
seq of
  StrictSeq a
SSeq.Empty -> forall a. Maybe a
Nothing
  StrictSeq a
xs' SSeq.:|> a
x -> forall a. a -> Maybe a
Just (forall a. StrictSeq a -> Set a -> OSet a
OSet StrictSeq a
xs' (a
x forall a. Ord a => a -> Set a -> Set a
`Set.delete` Set a
set), a
x)

-- | \(O(n \log n)\). Convert to an OSet from a List.
fromList :: Ord a => [a] -> OSet a
fromList :: forall a. Ord a => [a] -> OSet a
fromList = forall (f :: * -> *) a. (Foldable f, Ord a) => f a -> OSet a
fromFoldable

-- | Using a `Foldable` instance of the source data structure convert it to an `OSet`
fromFoldable :: (Foldable f, Ord a) => f a -> OSet a
fromFoldable :: forall (f :: * -> *) a. (Foldable f, Ord a) => f a -> OSet a
fromFoldable = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' forall a. Ord a => OSet a -> a -> OSet a
snoc forall a. OSet a
empty

-- | \(O(n \log n)\). Checks membership before snoc-ing.
-- De-duplicates the StrictSeq without overwriting.
fromStrictSeq :: Ord a => SSeq.StrictSeq a -> OSet a
fromStrictSeq :: forall a. Ord a => StrictSeq a -> OSet a
fromStrictSeq = forall (f :: * -> *) a. (Foldable f, Ord a) => f a -> OSet a
fromFoldable

-- | \(O(n \log n)\). Checks membership before snoc-ing.
-- Returns a 2-tuple, with `fst` as a `Set` of duplicates found
-- and the `snd` as the de-duplicated `OSet` without overwriting.
fromFoldableDuplicates :: (Foldable f, Ord a) => f a -> (Set.Set a, OSet a)
fromFoldableDuplicates :: forall (f :: * -> *) a.
(Foldable f, Ord a) =>
f a -> (Set a, OSet a)
fromFoldableDuplicates = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' forall a. Ord a => (Set a, OSet a) -> a -> (Set a, OSet a)
snoc' (forall a. Set a
Set.empty, forall a. OSet a
empty)
  where
    snoc' :: Ord a => (Set.Set a, OSet a) -> a -> (Set.Set a, OSet a)
    snoc' :: forall a. Ord a => (Set a, OSet a) -> a -> (Set a, OSet a)
snoc' (!Set a
duplicates, !oset :: OSet a
oset@(OSet StrictSeq a
seq Set a
set)) a
x =
      if a
x forall a. Ord a => a -> Set a -> Bool
`Set.member` Set a
set
        then (a
x forall a. Ord a => a -> Set a -> Set a
`Set.insert` Set a
duplicates, OSet a
oset)
        else (Set a
duplicates, forall a. StrictSeq a -> Set a -> OSet a
OSet (StrictSeq a
seq forall a. StrictSeq a -> a -> StrictSeq a
SSeq.|> a
x) (a
x forall a. Ord a => a -> Set a -> Set a
`Set.insert` Set a
set))

-- | \(O(n \log n)\). Checks membership before snoc-ing.
-- Returns a 2-tuple, with `fst` as a `Set` of duplicates found
-- and the `snd` as the de-duplicated `OSet` without overwriting.
-- Starts from the left or head, using `foldl'`
fromStrictSeqDuplicates :: Ord a => SSeq.StrictSeq a -> (Set.Set a, OSet a)
fromStrictSeqDuplicates :: forall a. Ord a => StrictSeq a -> (Set a, OSet a)
fromStrictSeqDuplicates = forall (f :: * -> *) a.
(Foldable f, Ord a) =>
f a -> (Set a, OSet a)
fromFoldableDuplicates

-- | \( O(1) \) -  Extract underlying strict sequence
toStrictSeq :: OSet a -> SSeq.StrictSeq a
toStrictSeq :: forall a. OSet a -> StrictSeq a
toStrictSeq = forall a. OSet a -> StrictSeq a
osSSeq

-- | \( O(1) \) -  Extract underlying Set
toSet :: OSet a -> Set.Set a
toSet :: forall a. OSet a -> Set a
toSet = forall a. OSet a -> Set a
osSet

-- | \( O(n) \).
fromSet :: Set.Set a -> OSet a
fromSet :: forall a. Set a -> OSet a
fromSet Set a
set = forall a. StrictSeq a -> Set a -> OSet a
OSet (forall a. [a] -> StrictSeq a
SSeq.fromList forall a b. (a -> b) -> a -> b
$ forall a. Set a -> [a]
Set.elems Set a
set) Set a
set

-- | \(O(\log n)\). Membership check.
member :: Ord a => a -> OSet a -> Bool
member :: forall a. Ord a => a -> OSet a -> Bool
member a
x (OSet StrictSeq a
_seq Set a
set) = a
x forall a. Ord a => a -> Set a -> Bool
`Set.member` Set a
set

-- | \( O(n \log n) \)
filter :: Ord a => (a -> Bool) -> OSet a -> OSet a
filter :: forall a. Ord a => (a -> Bool) -> OSet a -> OSet a
filter a -> Bool
f = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' (\OSet a
xs a
x -> if a -> Bool
f a
x then OSet a
xs forall a. Ord a => OSet a -> a -> OSet a
|> a
x else OSet a
xs) forall a. OSet a
empty

pattern Empty :: OSet a
pattern $bEmpty :: forall a. OSet a
$mEmpty :: forall {r} {a}. OSet a -> ((# #) -> r) -> ((# #) -> r) -> r
Empty <- (null -> True)
  where
    Empty = forall a. OSet a
empty

-- | \(O(\log n)\).
pattern (:<|:) :: Ord a => a -> OSet a -> OSet a
pattern x $b:<|: :: forall a. Ord a => a -> OSet a -> OSet a
$m:<|: :: forall {r} {a}.
Ord a =>
OSet a -> (a -> OSet a -> r) -> ((# #) -> r) -> r
:<|: xs <- (uncons -> Just (x, xs))
  where
    a
x :<|: OSet a
xs = a
x forall a. Ord a => a -> OSet a -> OSet a
<| OSet a
xs

infixr 5 :<|:

-- | \(O(\log n)\).
pattern (:|>:) :: Ord a => OSet a -> a -> OSet a
pattern xs $b:|>: :: forall a. Ord a => OSet a -> a -> OSet a
$m:|>: :: forall {r} {a}.
Ord a =>
OSet a -> (OSet a -> a -> r) -> ((# #) -> r) -> r
:|>: x <- (unsnoc -> Just (xs, x))
  where
    OSet a
xs :|>: a
x = OSet a
xs forall a. Ord a => OSet a -> a -> OSet a
|> a
x

infixl 5 :|>:

{-# COMPLETE Empty, (:|>:) #-}
{-# COMPLETE Empty, (:<|:) #-}

-- | \( O(n\log(m*n)) \). For every uncons-ed element from the sequence on the right,
-- checks its membership in the sequence on the left, before snoc'ing it.
-- Preserves order. Remove duplicates from sequence on the right.
(|><) :: Ord a => OSet a -> OSet a -> OSet a
OSet a
osetl |>< :: forall a. Ord a => OSet a -> OSet a -> OSet a
|>< OSet a
osetr = case OSet a
osetr of
  OSet a
Empty -> OSet a
osetl
  a
r :<|: OSet a
rs -> (OSet a
osetl forall a. Ord a => OSet a -> a -> OSet a
|> a
r) forall a. Ord a => OSet a -> OSet a -> OSet a
|>< OSet a
rs

infixl 5 |><

-- | \( O(m\log(m+n)) \). For every unsnoc-ed element from the sequence on the left,
-- checks its membership in the sequence on the right, before cons'ing it.
-- Preserves order. Remove duplicates from sequence on the left.
(><|) :: Ord a => OSet a -> OSet a -> OSet a
OSet a
osetl ><| :: forall a. Ord a => OSet a -> OSet a -> OSet a
><| OSet a
osetr = case OSet a
osetl of
  OSet a
Empty -> OSet a
osetr
  OSet a
ls :|>: a
l -> OSet a
ls forall a. Ord a => OSet a -> OSet a -> OSet a
><| (a
l forall a. Ord a => a -> OSet a -> OSet a
<| OSet a
osetr)

infixr 5 ><|