packages feed

creditmonad-1.0.0: src/Test/Credit/Finger.hs

{-# LANGUAGE GADTs, OverloadedLists, LambdaCase #-}

module Test.Credit.Finger where

import Prelude hiding (head, tail, last, init)
import Data.List.NonEmpty (NonEmpty(..), (<|))
import qualified Data.List.NonEmpty as NE
import Control.Monad (when, unless)
import Data.Foldable (foldlM, foldrM)
import Prettyprinter (Pretty)

import Control.Monad.Credit
import Test.Credit (linear, log2)
import qualified Test.Credit.Deque.Base as D
import qualified Test.Credit.Heap.Base as H
import qualified Test.Credit.RandomAccess.Base as RA
import qualified Test.Credit.Sortable.Base as S

data Digit a = One a | Two a a | Three a a a
  deriving (Eq, Ord, Show)

data Tuple v a = Pair v a a | Triple v a a a
  deriving (Eq, Ord, Show)

data FingerTree v a m
  = Empty
  | Single a
  | Deep (Thunk m (Lazy m) v) (Digit a) (Thunk m (FLazyCon m) (FingerTree v (Tuple v a) m)) (Digit a)

data FLazyCon m a where
  FPure :: a -> FLazyCon m a
  FCons :: Measured a v => a -> Thunk m (FLazyCon m) (FingerTree v a m) -> FLazyCon m (FingerTree v a m)
  FSnoc :: Measured a v => Thunk m (FLazyCon m) (FingerTree v a m) -> a -> FLazyCon m (FingerTree v a m)
  FTail :: Measured a v => FingerTree v a m -> FLazyCon m (FingerTree v a m)
  FInit :: Measured a v => FingerTree v a m -> FLazyCon m (FingerTree v a m)

instance MonadCredit m => HasStep (FLazyCon m) m where
  step (FPure xs) = pure xs
  step (FCons x m) = cons x =<< force m
  step (FSnoc m x) = flip snoc x =<< force m
  step (FTail q) = tail q
  step (FInit q) = init q

-- Main idea:
--  - cons, snoc, tail and init all cost two credits
--  - the first credit is used to tick
--  - We maintain the invariant: In each queue Deep(f, m, r), m has ||f| - 2| + ||r| - 2| credits.
--  - The m thunk requires two credits to force.
--  - snoc and tail spend their second credit on either the old m to be able to force it,
--    or on the new m to maintain the invariant.

class Monoid v => Measured a v where
  measure :: a -> v

instance Measured a v => Measured [a] v where
  measure = mconcat . map measure

instance Measured a v => Measured (Digit a) v where
  measure = measure . toList

instance Monoid v => Measured (Tuple v a) v where
  measure (Pair v _ _) = v
  measure (Triple v _ _ _) = v

measurement :: (MonadCredit m, Measured a v) => FingerTree v a m -> m v
measurement Empty = pure $ mempty
measurement (Single x) = pure $ measure x
measurement (Deep vm f m r) = do
  vm' <- force vm
  pure $ measure f <> vm' <> measure r

forceAll :: (MonadCredit m, Measured a v) => FingerTree v a m -> m ()
forceAll Empty = pure ()
forceAll (Single _) = pure ()
forceAll (Deep _ _ m _) = do
  creditWith m 2
  forceAll =<< force m

isTwo :: Digit a -> Bool
isTwo (Two _ _) = True
isTwo _ = False

empty :: MonadCredit m => m (Thunk m (FLazyCon m) (FingerTree v a m))
empty = delay $ FPure Empty

pair :: Measured a v => a -> a -> Tuple v a
pair x y = Pair (measure x <> measure y) x y

triple :: Measured a v => a -> a -> a -> Tuple v a
triple x y z = Triple (measure x <> measure y <> measure z) x y z

deep :: (MonadCredit m, Measured a v) => Thunk m (Lazy m) v -> Digit a -> Thunk m (FLazyCon m) (FingerTree v (Tuple v a) m) -> Digit a -> m (FingerTree v a m)
deep v f m r = do
  let oneIfDangerous d = if isTwo d then 0 else 1
  mIsPure <- lazymatch m (\_ -> pure True) $ \case
    FPure _ -> pure True
    _ -> pure False
  unless mIsPure $
    m `hasAtLeast` (oneIfDangerous f + oneIfDangerous r)
  pure $ Deep v f m r

deep' :: (MonadCredit m, Measured a v) => Digit a -> m (Thunk m (FLazyCon m) (FingerTree v (Tuple v a) m)) -> Digit a -> m (FingerTree v a m)
deep' f mkM r = do
  m <- mkM
  vm <- delay $ Lazy $ measurement =<< force m
  deep vm f m r

isEmpty :: FingerTree v a m -> Bool
isEmpty Empty = True
isEmpty _ = False

toList :: Digit a -> [a]
toList (One x) = [x]
toList (Two x y) = [x, y]
toList (Three x y z) = [x, y, z]

toTree :: (MonadCredit m, Measured a v) => [a] -> m (FingerTree v a m)
toTree [] = pure Empty
toTree [x] = pure $ Single x
toTree [x,y] = deep' (One x) empty (One y)
toTree [x,y,z] = deep' (Two x y) empty (One z)

toDigit :: Tuple v a -> Digit a
toDigit (Pair _ x y) = Two x y
toDigit (Triple _ x y z) = Three x y z

cons :: (MonadCredit m, Measured a v) => a -> FingerTree v a m -> m (FingerTree v a m)
cons x q = tick >> cons' x q

cons' :: (MonadCredit m, Measured a v) => a -> FingerTree v a m -> m (FingerTree v a m)
cons' x Empty = pure $ Single x
cons' x (Single y) = do
  deep' (One x) empty (One y)
cons' x (Deep vq pr q u) = case pr of
  One y       -> deep vq (Two x y) q u
  Two y z     -> creditWith q 1 >> pure (Deep vq (Three x y z) q u)
  Three y z w -> do
    q' <- delay $ FCons (pair z w) q
    if isTwo u
      then creditWith q 1
      else creditWith q' 1
    vq' <- delay $ Lazy $ measurement =<< force q'
    deep vq' (Two x y) q' u

head :: MonadCredit m => FingerTree v a m -> m a
head Empty = fail "head: empty queue"
head (Single x) = pure x
head (Deep _ s _ _) = pure $ let (h:_) = toList s in h

tail :: (MonadCredit m, Measured a v) => FingerTree v a m -> m (FingerTree v a m)
tail Empty = tick >> pure Empty
tail (Single _) = tick >> pure Empty
tail (Deep vq (Three _ x y) q u) = tick >> pure (Deep vq (Two x y) q u)
tail (Deep vq (Two _ x) q u) = tick >> creditWith q 1 >> pure (Deep vq (One x) q u)
tail (Deep _ (One _) q u) = tick >> do
  when (isTwo u) $ creditWith q 1
  q' <- force q
  deep0 q' u

deep0 :: (MonadCredit m, Measured a v) => FingerTree v (Tuple v a) m -> Digit a -> m (FingerTree v a m)
deep0 Empty s = toTree $ toList s
deep0 q u = do
  h <- head q
  case h of
    Pair _ x y -> do
      t <- delay $ FTail q
      unless (isTwo u) $ creditWith t 1
      vt <- delay $ Lazy $ measurement =<< force t
      deep vt (Two x y) t u
    Triple _ x _ _ -> do
      q' <- map1 chop q
      deep' (One x) (delay $ FPure q') u
      where chop (Triple _ _ y z) = pair y z

map1 :: (MonadCredit m, Measured a v) => (a -> a) -> FingerTree v a m -> m (FingerTree v a m)
map1 _ Empty = pure Empty
map1 f (Single x) = pure $ Single (f x)
map1 f (Deep vq (One x) q u) = deep vq (One (f x)) q u
map1 f (Deep vq (Two x y) q u) = deep vq (Two (f x) y) q u
map1 f (Deep vq (Three x y z) q u) = deep vq (Three (f x) y z) q u

uncons :: (MonadCredit m, Measured a v) => FingerTree v a m -> m (Maybe (a, FingerTree v a m))
uncons q =
  if isEmpty q
    then pure Nothing
    else do
      h <- head q
      t <- tail q
      pure $ Just (h, t)

deepL :: (MonadCredit m, Measured a v) => [a] -> Thunk m (Lazy m) v -> Thunk m (FLazyCon m) (FingerTree v (Tuple v a) m) -> Digit a -> m (FingerTree v a m)
deepL [] _ m sf = do
  m' <- uncons =<< force m
  case m' of
    Nothing -> toTree $ toList sf
    Just (Pair _ x y, m'') -> do
      deep' (Two x y) (delay $ FPure m'') sf
    Just (Triple _ x y z, m'') -> do
      deep' (Three x y z) (delay $ FPure m'') sf
deepL [x] vm m sf = deep vm (One x) m sf
deepL [x,y] vm m sf = deep vm (Two x y) m sf
deepL [x,y,z] vm m sf = deep vm (Three x y z) m sf

last :: (MonadCredit m, Measured a v) => FingerTree v a m -> m a
last Empty = fail "last: empty queue"
last (Single x) = pure x
last (Deep _ _ _ s) = pure $ let (h:_) = reverse $ toList s in h

snoc :: (MonadCredit m, Measured a v) => FingerTree v a m -> a -> m (FingerTree v a m)
snoc q y = tick >> snoc' q y

snoc' :: (MonadCredit m, Measured a v) => FingerTree v a m -> a -> m (FingerTree v a m)
snoc' Empty y = pure $ Single y
snoc' (Single x) y = deep' (One x) empty (One y)
snoc' (Deep vq u q (One x)) y = deep vq u q (Two x y)
snoc' (Deep vq u q (Two x y)) z = creditWith q 1 >> pure (Deep vq u q (Three x y z))
snoc' (Deep _ u q (Three x y z)) w = do
  q' <- delay $ FSnoc q (pair x y)
  if isTwo u
    then creditWith q 1
    else creditWith q' 1
  vq' <- delay $ Lazy $ measurement =<< force q'
  deep vq' u q' (Two z w)

init :: (MonadCredit m, Measured a v) => FingerTree v a m -> m (FingerTree v a m)
init Empty = tick >> pure Empty
init (Single _) = tick >> pure Empty
init (Deep vq u q (Three x y _)) = tick >> pure (Deep vq u q (Two x y))
init (Deep vq u q (Two x _)) = tick >> creditWith q 1 >> pure (Deep vq u q (One x))
init (Deep _ u q (One _)) = tick >> when (isTwo u) (creditWith q 1) >> force q >>= deepN u

deepN :: (MonadCredit m, Measured a v) => Digit a -> FingerTree v (Tuple v a) m -> m (FingerTree v a m)
deepN s Empty = toTree $ toList s
deepN u q = do
  l <- last q
  case l of
    Pair _ x y -> do
      t <- delay $ FInit q
      unless (isTwo u) $ creditWith t 1
      vt <- delay $ Lazy $ measurement =<< force t
      deep vt u t (Two x y)
    Triple _ _ _ z -> do
      q' <- mapN chop q
      deep' u (delay $ FPure q') (One z)
      where chop (Triple _ x y _) = pair x y

mapN :: (MonadCredit m, Measured a v) => (a -> a) -> FingerTree v a m -> m (FingerTree v a m)
mapN _ Empty = pure $ Empty
mapN f (Single x) = pure $ Single (f x)
mapN f (Deep vq u q (One x)) = deep vq u q (One (f x))
mapN f (Deep vq u q (Two x y)) = deep vq u q (Two x (f y))
mapN f (Deep vq u q (Three x y z)) = deep vq u q (Three x y (f z))

unsnoc :: (MonadCredit m, Measured a v) => FingerTree v a m -> m (Maybe (FingerTree v a m, a))
unsnoc q =
  if isEmpty q
    then pure Nothing
    else do
      h <- last q
      t <- init q
      pure $ Just (t, h)

deepR :: (MonadCredit m, Measured a v) => Digit a -> Thunk m (Lazy m) v -> Thunk m (FLazyCon m) (FingerTree v (Tuple v a) m) -> [a] -> m (FingerTree v a m)
deepR s _ m [] = do
  m' <- unsnoc =<< force m
  case m' of
    Nothing -> toTree $ toList s
    Just (m'', Pair _ x y) -> do
      deep' s (delay $ FPure m'') (Two x y)
    Just (m'', Triple _ x y z) -> do
      deep' s (delay $ FPure m'') (Three x y z)
deepR s vm m [x] = deep vm s m (One x)
deepR s vm m [x, y] = deep vm s m (Two x y)
deepR s vm m [x, y, z] = deep vm s m (Three x y z)

toTuples :: Measured a v => [a] -> [Tuple v a]
toTuples [] = []
toTuples [x, y] = [pair x y]
toTuples [x, y, z, w] = [pair x y, pair z w]
toTuples (x : y : z : xs) = triple x y z : toTuples xs

glue :: (MonadCredit m, Measured a v) => FingerTree v a m -> [a] -> FingerTree v a m -> m (FingerTree v a m)
glue Empty as q2 = foldrM cons q2 as
glue q1 as Empty = foldlM snoc q1 as
glue (Single x) as q2 = foldrM cons q2 (x : as)
glue q1 as (Single y) = foldlM snoc q1 (as ++ [y])
glue (Deep _ u1 q1 v1) as (Deep _ u2 q2 v2) = tick >> do
  creditWith q1 2
  q1 <- force q1
  creditWith q2 2
  q2 <- force q2
  q <- glue q1 (toTuples (toList v1 ++ as ++ toList u2)) q2
  deep' u1 (delay $ FPure q) v2

concat' :: (MonadCredit m, Measured a v) => FingerTree v a m -> FingerTree v a m -> m (FingerTree v a m)
concat' q1 q2 = glue q1 [] q2

data Split v a m = Split
  { measureOfSmaller :: v
  , smaller :: FingerTree v a m
  , found   :: a
  , bigger  :: FingerTree v a m
  }

splitDigit :: Measured a v => (v -> Bool) -> v -> Digit a -> ([a], a, [a])
splitDigit p i (One x) = ([], x, [])
splitDigit p i (Two x y)
  | p (i <> measure x) = ([], x, [y])
  | otherwise = ([x], y, [])
splitDigit p i (Three x y z)
  | p (i <> measure x) = ([], x, [y, z])
  | p (i <> measure x <> measure y) = ([x], y, [z])
  | otherwise = ([x, y], z, [])

-- For '(Split vml ml xs mr) <- splitTree p i m', we have 'vml = measurement ml'.
splitTree :: (MonadCredit m, Measured a v) => (v -> Bool) -> v -> FingerTree v a m -> m (Split v a m)
splitTree p i Empty = fail "splitTree: empty tree"
splitTree p i (Single x) = pure $ Split mempty Empty x Empty
splitTree p i (Deep vm pr m sf) = tick >> do
  vm' <- force vm
  let vpr = i <> measure pr
  let vprm = vpr <> vm'
  if p vpr then do
    let (l, x, r) = splitDigit p i pr
    Split (measure l) <$> toTree l <*> pure x <*> deepL r vm m sf
  else if p vprm then do
    Split vml ml xs mr <- splitTree p vpr =<< force m
    let (l, x, r) = splitDigit p (vpr <> vml) (toDigit xs)
    -- [ml', mr', vmr', vml'] <- mapM (delay . Lazy)
      -- [pure ml, pure mr, measurement mr, pure vml]
    ml' <- delay $ FPure ml
    mr' <- delay $ FPure mr
    vmr' <- delay $ Lazy $ measurement mr
    vml' <- delay $ Lazy $ pure vml
    Split (measure pr <> vml <> measure l) <$> deepR pr vml' ml' l <*> pure x <*> deepL r vmr' mr' sf
  else do
    let (l, x, r) = splitDigit p vprm sf
    Split (measure pr <> vm' <> measure l) <$> deepR pr vm m l <*> pure x <*> toTree r

split :: (MonadCredit m, Measured a v) => (v -> Bool) -> FingerTree v a m -> m (FingerTree v a m, FingerTree v a m)
split p Empty = pure (Empty, Empty)
split p xs = do
  forceAll xs
  mxs <- measurement xs
  if p mxs
    then do (Split _ l x r) <- splitTree p mempty xs
            (l,) <$> cons x r
    else pure (xs, Empty)

takeUntil :: (MonadCredit m, Measured a v) => (v -> Bool) -> FingerTree v a m -> m (FingerTree v a m)
takeUntil p m = fst <$> split p m

dropUntil :: (MonadCredit m, Measured a v) => (v -> Bool) -> FingerTree v a m -> m (FingerTree v a m)
dropUntil p m = snd <$> split p m

lookupTree :: (MonadCredit m, Measured a v) => (v -> Bool) -> v -> FingerTree v a m -> m (Maybe (v, a))
lookupTree p i Empty = pure Nothing
lookupTree p i t = do
  forceAll t
  (Split ml _ x _) <- splitTree p i t
  pure $ Just (i <> ml, x)

instance MemoryCell m a => MemoryCell m (Digit a) where
  prettyCell (One a) = do
    a' <- prettyCell a
    pure $ mkMCell "One" [a']
  prettyCell (Two a b) = do
    a' <- prettyCell a
    b' <- prettyCell b
    pure $ mkMCell "Two" [a', b']
  prettyCell (Three a b c) = do
    a' <- prettyCell a
    b' <- prettyCell b
    c' <- prettyCell c
    pure $ mkMCell "Three" [a', b', c']

instance MemoryCell m a => MemoryCell m (Tuple v a) where
  prettyCell (Pair _ a b) = do
    a' <- prettyCell a
    b' <- prettyCell b
    pure $ mkMCell "Pair" [a', b']
  prettyCell (Triple _ a b c) = do
    a' <- prettyCell a
    b' <- prettyCell b
    c' <- prettyCell c
    pure $ mkMCell "Triple" [a', b', c']

instance (MonadMemory m, MemoryCell m a) => MemoryCell m (FLazyCon m a) where
  prettyCell (FPure x) = do
    x' <- prettyCell x
    pure $ mkMCell "FPure" [x']
  prettyCell (FCons x m) = do
    -- x' <- prettyCell x
    m' <- prettyCell m
    pure $ mkMCell "FCons" [m']
  prettyCell (FSnoc m x) = do
    m' <- prettyCell m
    -- x' <- prettyCell x
    pure $ mkMCell "FSnoc" [m']
  prettyCell (FTail q) = do
    q' <- prettyCell q
    pure $ mkMCell "FTail" [q']
  prettyCell (FInit q) = do
    q' <- prettyCell q
    pure $ mkMCell "FInit" [q']

instance (MonadMemory m, MemoryCell m a) => MemoryCell m (FingerTree v a m) where
  prettyCell Empty = pure $ mkMCell "Empty" []
  prettyCell (Single a) = do
    a' <- prettyCell a
    pure $ mkMCell "Single" [a']
  prettyCell (Deep _ s q u) = do
    s' <- prettyCell s
    q' <- prettyCell q
    u' <- prettyCell u
    pure $ mkMCell "Deep" [s', q', u']

instance Pretty a => MemoryStructure (FingerTree v (PrettyCell a)) where
  prettyStructure = prettyCell

newtype Elem a = Elem a
  deriving (Eq, Ord, Show)

instance (MemoryCell m a) => MemoryCell m (Elem a) where
  prettyCell (Elem x) = prettyCell x

-- Deque

instance Measured (Elem a) () where
  measure (Elem x) = ()

newtype FingerDeque a m = FingerDeque (FingerTree () (Elem a) m)

instance D.Deque FingerDeque where
  empty = pure $ FingerDeque Empty
  cons x (FingerDeque q) = FingerDeque <$> cons (Elem x) q
  snoc (FingerDeque q) x = FingerDeque <$> snoc q (Elem x)
  uncons (FingerDeque q) = do
    m <- uncons q
    case m of
      Nothing -> pure Nothing
      Just (Elem x, q') -> pure $ Just (x, FingerDeque q')
  unsnoc (FingerDeque q) = do
    m <- unsnoc q
    case m of
      Nothing -> pure Nothing
      Just (q', Elem x) -> pure $ Just (FingerDeque q', x)
  concat (FingerDeque q1) (FingerDeque q2) = FingerDeque <$> concat' q1 q2

instance D.BoundedDeque FingerDeque where
  qcost _ (D.Cons _) = 2
  qcost _ (D.Snoc _) = 2
  qcost _ D.Uncons = 4
  qcost _ D.Unsnoc = 2
  qcost n D.Concat = 5 * log2 n

instance (MonadMemory m, MemoryCell m a) => MemoryCell m (FingerDeque a m) where
  prettyCell (FingerDeque q) = prettyCell q

instance Pretty a => MemoryStructure (FingerDeque (PrettyCell a)) where
  prettyStructure = prettyCell

-- Random Access

newtype Size = Size Int
  deriving (Eq, Ord, Show, Num)

instance Semigroup Size where
  x <> y = x + y

instance Monoid Size where
  mempty = 0

instance Measured (Elem a) Size where
  measure (Elem x) = 1

newtype FingerRA a m = FingerRA (FingerTree Size (Elem a) m)

-- Contrary to Hinze and Paterson, this is not O(1) but O(log n)
-- because we need to force all thunks in the tree to get the size.
length :: MonadCredit m => FingerRA a m -> m Size
length (FingerRA t) = measurement t

splitAt :: MonadCredit m => Int -> FingerRA a m -> m (FingerRA a m, FingerRA a m)
splitAt i (FingerRA xs) = do
   (l, r) <- split (fromIntegral i <) xs
   pure $ (FingerRA l, FingerRA r)

instance RA.RandomAccess FingerRA where
  empty = pure $ FingerRA Empty
  cons x (FingerRA q) = FingerRA <$> cons (Elem x) q
  uncons (FingerRA q) = do
    m <- uncons q
    case m of
      Nothing -> pure Nothing
      Just (Elem x, m') -> do
        pure $ Just (x, FingerRA m')
  lookup i (FingerRA Empty) = pure Nothing
  lookup i (FingerRA xs) = do
    forceAll xs
    (Split _ _ (Elem x) _) <- splitTree (fromIntegral i <) 0 xs
    pure $ Just x
  update i a (FingerRA Empty) = pure $ FingerRA Empty
  update i a (FingerRA xs) = do
    forceAll xs
    (Split ml l (Elem x) r) <- splitTree (fromIntegral i <) 0 xs
    if fromIntegral i > ml
      then FingerRA <$> snoc l (Elem x)
      else FingerRA <$> (concat' l =<< cons (Elem a) r)

instance RA.BoundedRandomAccess FingerRA where
  qcost n (RA.Cons _) = 2
  qcost n RA.Uncons = 2
  qcost n (RA.Lookup i) = 5 * log2 n
  qcost n (RA.Update i _) = 2 + 10 * log2 n

instance (MonadMemory m, MemoryCell m a) => MemoryCell m (FingerRA a m) where
  prettyCell (FingerRA q) = prettyCell q

instance Pretty a => MemoryStructure (FingerRA (PrettyCell a)) where
  prettyStructure = prettyCell

-- Heap

data Prio a = MInfty | Prio a
  deriving (Eq, Ord, Show)

instance Ord a => Semigroup (Prio a) where
  MInfty <> p = p
  p <> MInfty = p
  Prio x <> Prio y = Prio (min x y)

instance Ord a => Monoid (Prio a) where
  mempty = MInfty

instance Ord a => Measured (Elem a) (Prio a) where
  measure (Elem x) = Prio x

newtype FingerHeap a m = FingerHeap (FingerTree (Prio a) (Elem a) m)

instance H.Heap FingerHeap where
  empty = pure $ FingerHeap Empty
  insert x (FingerHeap xs) = FingerHeap <$> cons (Elem x) xs
  merge (FingerHeap a) (FingerHeap b) = FingerHeap <$> concat' a b
  splitMin (FingerHeap Empty) = pure Nothing
  splitMin (FingerHeap xs) = do
    forceAll xs -- 2 * log n
    k <- measurement xs
    (Split _ l (Elem x) r) <- splitTree (k >=) mempty xs -- 3 * log n
    lr <- concat' l r -- 5 log n
    pure $ Just (x, FingerHeap lr)

instance H.BoundedHeap FingerHeap where
  hcost n (H.Insert _) = 2
  hcost n H.Merge = 5 * log2 n
  hcost n H.SplitMin = 1 + 10 * log2 (n + 1)

instance (MonadMemory m, MemoryCell m a) => MemoryCell m (FingerHeap a m) where
  prettyCell (FingerHeap q) = prettyCell q

instance Pretty a => MemoryStructure (FingerHeap (PrettyCell a)) where
  prettyStructure = prettyCell

-- Sortable Collection

data Key a = NoKey | Key a
  deriving (Eq, Ord, Show)

instance Semigroup (Key a) where
  k <> NoKey = k
  _ <> k = k

instance Monoid (Key a) where
  mempty = NoKey

instance Measured (Elem a) (Key a) where
  measure (Elem x) = Key x

newtype FingerSort a m = FingerSort (FingerTree (Key a) (Elem a) m)

rev :: MonadCredit m => [a] -> [a] -> m [a]
rev [] acc = pure acc
rev (x : xs) acc = tick >> rev xs (x : acc) 

append :: MonadCredit m => [a] -> [a] -> m [a]
append [] ys = pure ys
append (x : xs) ys = tick >> fmap (x:) (append xs ys)

treeToList :: MonadCredit m => [b] -> (a -> m [b]) -> FingerTree v a m -> m [b]
treeToList acc f Empty = rev acc []
treeToList acc f (Single x) = do
  fx <- f x
  flip rev [] =<< append fx acc
treeToList acc f (Deep _ s q u) = do
  s' <- fmap (concatMap id) $ traverse f $ toList s
  u' <- fmap (concatMap id) $ traverse f $ toList u
  creditWith q 2
  q' <- treeToList (u' ++ acc) (fmap (concatMap id) . traverse f . toList . toDigit) =<< force q
  append s' q'

instance S.Sortable FingerSort where
  empty = pure $ FingerSort Empty
  add x (FingerSort xs) = do
    (l, r) <- split (>= Key x) xs
    lxr <- concat' l =<< cons (Elem x) r
    pure $ FingerSort lxr
  sort (FingerSort xs) = do
    treeToList [] (\(Elem x) -> tick >> pure [x]) xs

instance S.BoundedSortable FingerSort where
  scost n (S.Add _) = 1 + 10 * log2 (n + 1)
  scost n S.Sort = 2 * log2 n + 3 * linear n

instance (MonadMemory m, MemoryCell m a) => MemoryCell m (FingerSort a m) where
  prettyCell (FingerSort q) = prettyCell q

instance Pretty a => MemoryStructure (FingerSort (PrettyCell a)) where
  prettyStructure = prettyCell