seqn-0.1.0.0: src/Data/Seqn/Internal/MTree.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_HADDOCK not-home #-}
-- |
-- This is an internal module. You probably don't need to import this. Use
-- "Data.Seqn.MSeq" instead.
--
-- = WARNING
--
-- Definitions in this module allow violating invariants that would otherwise be
-- guaranteed by "Data.Seqn.MSeq". Use at your own risk!
--
module Data.Seqn.Internal.MTree
(
-- * Measured
Measured(..)
-- * MTree
, MTree(..)
-- * Basic
, singleton
, size
, (<>>)
, (<<>)
, bin
, binn
-- * Folds
, foldMap
, foldl'
, foldr'
, ifoldl'
, ifoldr'
, traverse
, ifoldMap
, itraverse
-- * Construct
, generateA
-- * Index
, index
, adjustF
, insertAt
, deleteAt
-- * Slice
, cons
, snoc
, uncons
, unconsSure
, unsnoc
, unsnocSure
, splitAtF
-- * Transform
, mapMaybeA
, mapEitherA
-- * Force
, liftRnf2
-- * Zip and unzip
, zipWithStreamM
, unzipWithA
, unzipWith3A
-- * Tree helpers
, fold
, foldSimple
, link
, merge
, glue
, balanceL
, balanceR
-- * Testing
, valid
, debugShowsPrec
) where
import Prelude hiding (foldMap, foldl', traverse)
import qualified Control.Applicative as Ap
import Control.DeepSeq (NFData(..))
import Data.Bifunctor (Bifunctor(..))
import Data.Coerce (coerce)
import Data.Seqn.Internal.Stream (Stream(..), Step(..))
import qualified Data.Seqn.Internal.Util as U
-------------
-- Measured
-------------
-- | Types that have a combinable property, called the measure.
class Semigroup (Measure a) => Measured a where
type Measure a
-- | Calculate the measure of a value.
measure :: a -> Measure a
----------
-- MTree
----------
data MTree a
= MBin {-# UNPACK #-} !Int !(Measure a) !a !(MTree a) !(MTree a)
| MTip
--------------
-- Instances
--------------
instance (NFData (Measure a), NFData a) => NFData (MTree a) where
rnf = \case
MBin _ v x l r -> rnf v `seq` rnf x `seq` rnf l `seq` rnf r
MTip -> ()
{-# INLINABLE rnf #-}
liftRnf2 :: (Measure a -> ()) -> (a -> ()) -> MTree a -> ()
liftRnf2 g f = go
where
go (MBin _ v x l r) = g v `seq` f x `seq` go l `seq` go r
go MTip = ()
{-# INLINE liftRnf2 #-}
--------------
-- Basic ops
--------------
singleton :: Measured a => a -> MTree a
singleton x = MBin 1 (measure x) x MTip MTip
{-# INLINE singleton #-}
size :: MTree a -> Int
size (MBin n _ _ _ _) = n
size MTip = 0
{-# INLINE size #-}
infixr 6 <>>
infixr 6 <<>
(<>>) :: Measured a => MTree a -> Measure a -> Measure a
MBin _ v _ _ _ <>> x = v <> x
MTip <>> x = x
{-# INLINE (<>>) #-}
(<<>) :: Measured a => Measure a -> MTree a -> Measure a
x <<> MBin _ v _ _ _ = x <> v
x <<> MTip = x
{-# INLINE (<<>) #-}
-- O(1). Link two trees with a value in between. Precondition: The trees are
-- balanced wrt each other.
bin :: Measured a => a -> MTree a -> MTree a -> MTree a
bin x l r = MBin (size l + size r + 1) (l <>> measure x <<> r) x l r
{-# INLINE bin #-}
-- O(1). Link two trees with a value in between and a known total size.
-- Precondition: The trees are balanced wrt each other.
binn :: Measured a => Int -> a -> MTree a -> MTree a -> MTree a
binn n x l r = MBin n (l <>> measure x <<> r) x l r
{-# INLINE binn #-}
----------
-- Folds
----------
-- See Note [Folds] in Data.Seqn.Internal.Seq
foldl' :: (b -> a -> b) -> b -> MTree a -> b
foldl' f !z0 = \case
MBin _ _ x l r -> go z0 x l r
MTip -> z0
where
go !z !x l r = case l of
MBin _ _ lx ll lr -> case r of
MBin _ _ rx rl rr ->
let !z' = go z lx ll lr
in go (f z' x) rx rl rr
MTip ->
let !z' = go z lx ll lr
in f z' x
MTip -> case r of
MBin _ _ rx rl rr -> go (f z x) rx rl rr
MTip -> f z x
{-# INLINE foldl' #-}
ifoldl' :: (Int -> b -> a -> b) -> b -> Int -> MTree a -> b
ifoldl' f !z0 !i0 = \case
MBin _ _ x l r -> go z0 i0 x l r
MTip -> z0
where
go !z !i !x l r = case l of
MBin lsz _ lx ll lr -> case r of
MBin _ _ rx rl rr ->
let !z' = go z i lx ll lr
in go (f (i+lsz) z' x) (i+lsz+1) rx rl rr
MTip ->
let !z' = go z i lx ll lr
in f (i+lsz) z' x
MTip -> case r of
MBin _ _ rx rl rr -> go (f i z x) (i+1) rx rl rr
MTip -> f i z x
{-# INLINE ifoldl' #-}
foldr' :: (a -> b -> b) -> b -> MTree a -> b
foldr' f !z0 = \case
MBin _ _ x l r -> go z0 x l r
MTip -> z0
where
go !z !x l r = case l of
MBin _ _ lx ll lr -> case r of
MBin _ _ rx rl rr ->
let !z' = go z rx rl rr
in go (f x z') lx ll lr
MTip -> go (f x z) lx ll lr
MTip -> case r of
MBin _ _ rx rl rr -> f x $! go z rx rl rr
MTip -> f x z
{-# INLINE foldr' #-}
ifoldr' :: (Int -> a -> b -> b) -> b -> Int -> MTree a -> b
ifoldr' f !z0 !i0 = \case
MBin _ _ x l r -> go z0 i0 x l r
MTip -> z0
where
go !z !i !x l r = case l of
MBin _ _ lx ll lr -> case r of
MBin rsz _ rx rl rr ->
let !z' = go z i rx rl rr
in go (f (i-rsz) x z') (i-rsz-1) lx ll lr
MTip -> go (f i x z) (i-1) lx ll lr
MTip -> case r of
MBin rsz _ rx rl rr -> f (i-rsz) x $! go z i rx rl rr
MTip -> f i x z
{-# INLINE ifoldr' #-}
fold
:: b
-> (Int -> a -> b -> b -> b)
-> (Int -> a -> b -> b)
-> (Int -> a -> b -> b)
-> (a -> b)
-> MTree a
-> b
fold tip glr gl gr g = \case
MBin sz _ x l r -> go sz x l r
MTip -> tip
where
go !sz !x l r = case l of
MBin lsz _ lx ll lr -> case r of
MBin rsz _ rx rl rr -> glr sz x (go lsz lx ll lr) (go rsz rx rl rr)
MTip -> gl sz x (go lsz lx ll lr)
MTip -> case r of
MBin rsz _ rx rl rr -> gr sz x (go rsz rx rl rr)
MTip -> g x
{-# INLINE fold #-}
foldSimple :: b -> (Int -> a -> b -> b -> b) -> MTree a -> b
foldSimple tip f = fold tip f gl gr g
where
gl !sz x ml = f sz x ml tip
{-# INLINE gl #-}
gr !sz x mr = f sz x tip mr
{-# INLINE gr #-}
g x = f 1 x tip tip
{-# INLINE g #-}
{-# INLINE foldSimple #-}
foldMap :: forall a m. Monoid m => (a -> m) -> MTree a -> m
foldMap f = coerce (fold @m @a) (mempty @m) glr gl gr f
where
glr (_ :: Int) x l r = l <> f x <> r
{-# INLINE glr #-}
gl (_ :: Int) x l = l <> f x
{-# INLINE gl #-}
gr (_ :: Int) x r = f x <> r
{-# INLINE gr #-}
{-# INLINE foldMap #-}
traverse :: (Measured b, Applicative f) => (a -> f b) -> MTree a -> f (MTree b)
traverse f = fold (pure MTip) glr gl gr g
where
glr !sz x ml mr = Ap.liftA3 (flip (binn sz)) ml (f x) mr
{-# INLINE glr #-}
gl !sz x ml = Ap.liftA2 (\l' x' -> binn sz x' l' MTip) ml (f x)
{-# INLINE gl #-}
gr !sz x mr = Ap.liftA2 (\x' r' -> binn sz x' MTip r') (f x) mr
{-# INLINE gr #-}
g x = fmap singleton (f x)
{-# INLINE g #-}
{-# INLINE traverse #-}
ifoldMap :: Monoid m => (Int -> a -> m) -> Int -> MTree a -> m
ifoldMap f !i0 = \case
MBin _ _ x l r -> go i0 x l r
MTip -> mempty
where
go !i x l r = case l of
MBin lsz _ lx ll lr -> case r of
MBin _ _ rx rl rr ->
go i lx ll lr <> f (i+lsz) x <> go (i+lsz+1) rx rl rr
MTip -> go i lx ll lr <> f (i+lsz) x
MTip -> case r of
MBin _ _ rx rl rr -> f i x <> go (i+1) rx rl rr
MTip -> f i x
{-# INLINE ifoldMap #-}
itraverse
:: (Measured b, Applicative f)
=> (Int -> a -> f b) -> Int -> MTree a -> f (MTree b)
itraverse f !i0 = \case
MBin sz _ x l r -> go i0 sz x l r
MTip -> pure MTip
where
go !i !sz x l r = case l of
MBin lsz _ lx ll lr -> case r of
MBin rsz _ rx rl rr ->
Ap.liftA3
(flip (binn sz))
(go i lsz lx ll lr)
(f (i+lsz) x)
(go (i+lsz+1) rsz rx rl rr)
MTip ->
Ap.liftA2
(\l' x' -> binn sz x' l' MTip)
(go i lsz lx ll lr)
(f (i+lsz) x)
MTip -> case r of
MBin rsz _ rx rl rr ->
Ap.liftA2
(\x' r' -> binn sz x' MTip r')
(f i x)
(go (i+1) rsz rx rl rr)
MTip ->
fmap singleton (f i x)
{-# INLINE itraverse #-}
-----------------
-- Construction
-----------------
generateA
:: (Measured a, Applicative f)
=> (Int -> f a) -> Int -> Int -> f (MTree a)
generateA f = go
where
go !i n
| n <= 0 = pure MTip
| otherwise =
Ap.liftA3
(flip (binn n))
(go i lsz)
(f (i+lsz))
(go (i+lsz+1) (n-lsz-1))
where
lsz = (n-1) `div` 2
{-# INLINE generateA #-}
-------------
-- Indexing
-------------
-- Precondition: 0 <= i < size xs
index :: Int -> MTree a -> a
index !i = \case
MBin _ _ x l r -> case compare i szl of
LT -> index i l
EQ -> x
GT -> index (i-szl-1) r
where
szl = size l
MTip -> errorOutOfBounds "MTree.index"
-- Precondition: 0 <= i < size xs
adjustF
:: (Measured a, Functor f)
=> (a -> f a) -> Int -> MTree a -> f (MTree a)
adjustF f = go
where
go !i = \case
MBin sz _ x l r -> case compare i szl of
LT -> fmap (\l' -> binn sz x l' r) (go i l)
EQ -> fmap (\x' -> binn sz x' l r) (f x)
GT -> fmap (binn sz x l) (go (i-szl-1) r)
where
szl = size l
MTip -> errorOutOfBounds "MTree.adjustF"
{-# INLINE adjustF #-}
-- Inserts at ends if not in bounds
insertAt :: Measured a => Int -> a -> MTree a -> MTree a
insertAt !i x (MBin _ _ y l r)
| i <= szl = balanceL y (insertAt i x l) r
| otherwise = balanceR y l (insertAt (i-szl-1) x r)
where
szl = size l
insertAt _ x MTip = singleton x
{-# INLINABLE insertAt #-}
-- Precondition: 0 <= i < size xs
deleteAt :: Measured a => Int -> MTree a -> MTree a
deleteAt !i (MBin _ _ x l r) = case compare i szl of
LT -> balanceR x (deleteAt i l) r
EQ -> glue l r
GT -> balanceL x l (deleteAt (i-szl-1) r)
where
szl = size l
deleteAt _ MTip = errorOutOfBounds "MTree.deleteAt"
{-# INLINABLE deleteAt #-}
----------
-- Slice
----------
cons :: Measured a => a -> MTree a -> MTree a
cons x MTip = singleton x
cons x (MBin _ _ y l r) = balanceL y (cons x l) r
{-# INLINABLE cons #-}
snoc :: Measured a => MTree a -> a -> MTree a
snoc MTip x = singleton x
snoc (MBin _ _ y l r) x = balanceR y l (snoc r x)
{-# INLINABLE snoc #-}
uncons :: Measured a => MTree a -> U.SMaybe (U.S2 a (MTree a))
uncons (MBin _ _ x l r) = U.SJust (unconsSure x l r)
uncons MTip = U.SNothing
{-# INLINE uncons #-}
unconsSure :: Measured a => a -> MTree a -> MTree a -> U.S2 a (MTree a)
unconsSure x (MBin _ _ lx ll lr) r = case unconsSure lx ll lr of
U.S2 y l' -> U.S2 y (balanceR x l' r)
unconsSure x MTip r = U.S2 x r
{-# INLINABLE unconsSure #-}
unsnoc :: Measured a => MTree a -> U.SMaybe (U.S2 (MTree a) a)
unsnoc (MBin _ _ x l r) = U.SJust $ unsnocSure x l r
unsnoc MTip = U.SNothing
{-# INLINE unsnoc #-}
unsnocSure :: Measured a => a -> MTree a -> MTree a -> U.S2 (MTree a) a
unsnocSure x l (MBin _ _ rx rl rr) = case unsnocSure rx rl rr of
U.S2 r' y -> U.S2 (balanceL x l r') y
unsnocSure x l MTip = U.S2 l x
{-# INLINABLE unsnocSure #-}
-- Precondition: 0 <= i < size xs
splitAtF
:: (Measured a, U.Biapplicative f)
=> Int -> MTree a -> f (MTree a) (U.S2 a (MTree a))
splitAtF = go
where
go !i (MBin _ _ x l r) = case compare i szl of
LT -> second (second (\lr -> link x lr r)) (go i l)
EQ -> U.bipure l (U.S2 x r)
GT -> first (link x l) (go (i-szl-1) r)
where
szl = size l
go _ MTip = errorOutOfBounds "MTree.splitAtF"
{-# INLINE splitAtF #-}
--------------
-- Transform
--------------
mapMaybeA
:: (Applicative f, Measured b)
=> (a -> f (Maybe b)) -> MTree a -> f (MTree b)
mapMaybeA f = foldSimple tip g
where
tip = pure MTip
{-# INLINE tip #-}
g _ x ml mr = (\h -> Ap.liftA3 h ml (f x) mr) $ \l my r ->
case my of
Nothing -> merge l r
Just y -> link y l r
{-# INLINE g #-}
{-# INLINE mapMaybeA #-}
mapEitherA
:: (Applicative f, Measured b, Measured c)
=> (a -> f (Either b c)) -> MTree a -> f (U.S2 (MTree b) (MTree c))
mapEitherA f = foldSimple tip g
where
tip = pure (U.bipure MTip MTip)
{-# INLINE tip #-}
g _ x ml mr = (\h -> Ap.liftA3 h ml (f x) mr) $ \l my r ->
case my of
Left y -> U.biliftA2 (link y) merge l r
Right y -> U.biliftA2 merge (link y) l r
{-# INLINE g #-}
{-# INLINE mapEitherA #-}
------------------
-- Zip and unzip
------------------
zipWithStreamM
:: (Measured c, Monad m)
=> (a -> b -> m c) -> MTree a -> Stream b -> m (MTree c)
zipWithStreamM f t (Stream step s) = U.evalSStateT (foldSimple tip g t) s
where
tip = pure MTip
{-# INLINE tip #-}
g _ x ml mr = U.SStateT $ \s2 -> do
U.S2 s3 l <- U.runSStateT ml s2
case step s3 of
Done -> pure $ U.S2 s3 l
Yield y s4 -> do
z <- f x y
U.S2 s5 r <- U.runSStateT mr s4
pure $! U.S2 s5 (link z l r)
{-# INLINE g #-}
{-# INLINE zipWithStreamM #-}
unzipWithA
:: (Measured b, Measured c, Applicative f)
=> (a -> f (b, c)) -> MTree a -> f (U.S2 (MTree b) (MTree c))
unzipWithA f = foldSimple tip g
where
tip = pure (U.S2 MTip MTip)
{-# INLINE tip #-}
g !sz x ml mr = Ap.liftA3 bin2 ml (f x) mr
where
bin2 (U.S2 l1 l2) (x1,x2) (U.S2 r1 r2) =
U.S2 (binn sz x1 l1 r1) (binn sz x2 l2 r2)
{-# INLINE g #-}
{-# INLINE unzipWithA #-}
unzipWith3A
:: (Measured b, Measured c, Measured d, Applicative f)
=> (a -> f (b, c, d))
-> MTree a
-> f (U.S3 (MTree b) (MTree c) (MTree d))
unzipWith3A f = foldSimple tip g
where
tip = pure (U.S3 MTip MTip MTip)
{-# INLINE tip #-}
g !sz x ml mr = Ap.liftA3 bin3 ml (f x) mr
where
bin3 (U.S3 l1 l2 l3) (x1,x2,x3) (U.S3 r1 r2 r3) =
U.S3 (binn sz x1 l1 r1) (binn sz x2 l2 r2) (binn sz x3 l3 r3)
{-# INLINE g #-}
{-# INLINE unzipWith3A #-}
-----------
-- Errors
-----------
errorOutOfBounds :: String -> a
errorOutOfBounds name = error (name ++ ": out of bounds")
------------
-- Balance
------------
-- O(|log n1 - log n2|). Link two trees with a value in between.
link :: Measured a => a -> MTree a -> MTree a -> MTree a
link !x MTip r = cons x r
link x l MTip = snoc l x
link x l@(MBin ls lv lx ll lr) r@(MBin rs rv rx rl rr)
| delta*ls < rs = balanceL rx (linkL x ls l rl) rr
| delta*rs < ls = balanceR lx ll (linkR x lr rs r)
| otherwise = MBin (1+ls+rs) (lv <> measure x <> rv) x l r
{-# INLINE link #-}
linkL :: Measured a => a -> Int -> MTree a -> MTree a -> MTree a
linkL !x !ls !l r = case r of
MBin rs rv rx rl rr
| delta*ls < rs -> balanceL rx (linkL x ls l rl) rr
| otherwise -> MBin (1+ls+rs) (l <>> measure x <> rv) x l r
MTip -> error "MTree.linkL: impossible"
{-# INLINABLE linkL #-}
linkR :: Measured a => a -> MTree a -> Int -> MTree a -> MTree a
linkR !x l !rs !r = case l of
MBin ls lv lx ll lr
| delta*rs < ls -> balanceR lx ll (linkR x lr rs r)
| otherwise -> MBin (1+ls+rs) (lv <> measure x <<> r) x l r
MTip -> error "MTree.linkR: impossible"
{-# INLINABLE linkR #-}
-- O(log (n1 + n2)). Link two trees.
merge :: Measured a => MTree a -> MTree a -> MTree a
merge MTip r = r
merge l MTip = l
merge l@(MBin ls _ lx ll lr) r@(MBin rs _ rx rl rr)
| ls < rs = case unsnocSure lx ll lr of U.S2 l' mx -> link mx l' r
| otherwise = case unconsSure rx rl rr of U.S2 mx r' -> link mx l r'
{-# INLINE merge #-}
-- O(log (n1 + n2)). Link two trees. Precondition: The trees must be balanced
-- wrt each other.
glue :: Measured a => MTree a -> MTree a -> MTree a
glue MTip r = r
glue l MTip = l
glue l@(MBin ls _ lx ll lr) r@(MBin rs _ rx rl rr)
| ls > rs = case unsnocSure lx ll lr of U.S2 l' m -> balanceR m l' r
| otherwise = case unconsSure rx rl rr of U.S2 m r' -> balanceL m l r'
{-# INLINE glue #-}
-- See Note [Balance] in Data.Seqn.Internal.Tree
delta, ratio :: Int
delta = 3
ratio = 2
-- O(1). Restores balance with at most one right rotation. Precondition: One
-- right rotation must be enough to restore balance. This is the case when the
-- left tree might have been inserted to or the right tree deleted from.
balanceL :: Measured a => a -> MTree a -> MTree a -> MTree a
balanceL !x l r = case r of
MTip -> case l of
MTip -> MBin 1 v x MTip MTip
MBin _ lv lx ll lr -> case lr of
MTip -> case ll of
MTip -> MBin 2 (lv <> v) x l MTip
MBin _ _ _ _ _ ->
MBin 3 (lv <> v) lx ll (MBin 1 v x MTip MTip)
MBin _ lrv lrx _ _ -> case ll of
MTip ->
MBin 3
(lv <> v)
lrx
(MBin 1 (measure lx) lx MTip MTip)
(MBin 1 v x MTip MTip)
MBin _ _ _ _ _ ->
MBin 4 (lv <> v) lx ll (MBin 2 (lrv <> measure x) x lr MTip)
MBin rs rv _ _ _ -> case l of
MTip -> MBin (1+rs) (v <> rv) x MTip r
MBin ls lv lx ll lr
| ls > delta*rs -> case (ll, lr) of
(MBin lls llv _ _ _, MBin lrs lrv lrx lrl lrr)
| lrs < ratio*lls ->
MBin (1+ls+rs)
(lv <> v <> rv)
lx
ll
(MBin (1+rs+lrs) (lrv <> v <> rv) x lr r)
| otherwise ->
MBin (1+ls+rs)
(lv <> v <> rv)
lrx
(MBin (1+lls+size lrl) (llv <> measure lx <<> lrl) lx ll lrl)
(MBin (1+rs+size lrr) (lrr <>> v <> rv) x lrr r)
_ -> error "MTree.balanceL: impossible"
| otherwise -> MBin (1+ls+rs) (lv <> v <> rv) x l r
where
v = measure x
{-# INLINABLE balanceL #-}
-- O(1). Restores balance with at most one left rotation. Precondition: One left
-- rotation must be enough to restore balance. This is the case when the right
-- tree might have been inserted to or the left tree deleted from.
balanceR :: Measured a => a -> MTree a -> MTree a -> MTree a
balanceR !x l r = case l of
MTip -> case r of
MTip -> MBin 1 v x MTip MTip
MBin _ rv rx rl rr -> case rl of
MTip -> case rr of
MTip -> MBin 2 (v <> rv) x MTip r
MBin _ _ _ _ _ -> MBin 3 (v <> rv) rx (MBin 1 v x MTip MTip) rr
MBin _ rlv rlx _ _ -> case rr of
MTip ->
MBin 3
(v <> rv)
rlx
(MBin 1 v x MTip MTip)
(MBin 1 (measure rx) rx MTip MTip)
MBin _ _ _ _ _ ->
MBin 4 (v <> rv) rx (MBin 2 (v <> rlv) x MTip rl) rr
MBin ls lv _ _ _ -> case r of
MTip -> MBin (1+ls) (lv <> v) x l MTip
MBin rs rv rx rl rr
| rs > delta*ls -> case (rl, rr) of
(MBin rls rlv rlx rll rlr, MBin rrs rrv _ _ _)
| rls < ratio*rrs ->
MBin (1+ls+rs)
(lv <> v <> rv)
rx
(MBin (1+ls+rls) (lv <> v <> rlv) x l rl)
rr
| otherwise ->
MBin (1+ls+rs)
(lv <> v <> rv)
rlx
(MBin (1+ls+size rll) (lv <> v <<> rll) x l rll)
(MBin (1+rrs+size rlr) (rlr <>> measure rx <> rrv) rx rlr rr)
_ -> error "MTree.balanceR: impossible"
| otherwise -> MBin (1+ls+rs) (lv <> v <> rv) x l r
where
v = measure x
{-# INLINABLE balanceR #-}
------------
-- Testing
------------
valid :: (Measured a, Eq (Measure a)) => MTree a -> Bool
valid s = balanceOk s && sizeOk s && measureOk s
where
balanceOk = \case
MBin _ _ _ l r -> ok && balanceOk l && balanceOk r
where
ok = size l + size r <= 1 ||
(size l <= delta * size r && size r <= delta * size l)
MTip -> True
sizeOk = \case
MBin sz _ _ l r -> sizeOk l && sizeOk r && size l + size r + 1 == sz
MTip -> True
measureOk = \case
MBin _ v x l r ->
measureOk l && measureOk r && l <>> measure x <<> r == v
MTip -> True
debugShowsPrec :: (Show a, Show (Measure a)) => Int -> MTree a -> ShowS
debugShowsPrec p = \case
MBin sz v x l r ->
showParen (p > 10) $
showString "MBin " .
shows sz .
showString " " .
showsPrec 11 v .
showString " " .
showsPrec 11 x .
showString " " .
debugShowsPrec 11 l .
showString " " .
debugShowsPrec 11 r
MTip -> showString "MTip"