packages feed

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

{-# LANGUAGE GADTs, LambdaCase #-}

module Test.Credit.Finger where

import Prelude hiding (head, tail, last, init)
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 v (Digit a) (Thunk m (FLazyCon m) (FingerTree v (Tuple v a) m)) (Digit a)

data FLazyCon m a where
  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 (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 (Eq v, Monoid v) => Measured a v where
  measure :: a -> v

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

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

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

instance (Measured a v, Measured b v) => Measured (a, b) v where
  measure (x, y) = measure x <> measure y

instance (Measured a v, Measured b v, Measured c v) => Measured (a, b, c) v where
  measure (x, y, z) = measure x <> measure y <> measure z

instance (Measured a v, Measured b v) => Measured (Either a b) v where
  measure (Left x) = measure x
  measure (Right y) = measure y

instance Measured a v => Measured (Maybe a) v where
  measure Nothing = mempty
  measure (Just a) = measure a

instance Measured a v => Measured (FingerTree v a m) v where
  measure Empty = mempty
  measure (Single x) = measure x
  measure (Deep vm f m r) = measure f <> vm <> measure r

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

empty :: MonadCredit m => m (Thunk m (FLazyCon m) (FingerTree v a m))
empty = value $ 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) => 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 dang d = if isTwo d then 0 else 1
  m `hasAtLeast` (dang f + dang r)
  lazymatch m (\m -> when (v /= measure m) $ error "invalid measure") (\_ -> pure ())
  pure $ Deep v f m r

deep' :: (MonadCredit m, Measured a v) => v -> Digit a -> m (Thunk m (FLazyCon m) (FingerTree v (Tuple v a) m)) -> Digit a -> m (FingerTree v a m)
deep' vm f mkM r = do
  m <- mkM
  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' mempty (One x) empty (One y)
toTree [x,y,z] = deep' mempty (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 = do
  tick
  case q of
    Empty -> pure $ Single x
    Single y -> do
      deep' mempty (One x) empty (One y)
    Deep vq (One y) q u -> do
      deep vq (Two x y) q u
    Deep vq (Two y z) q u -> do
      q `creditWith` 1
      deep vq (Three x y z) q u
    Deep vq (Three y z w) q u -> do
      q' <- delay $ FCons (pair z w) q
      if isTwo u
        then q  `creditWith` 1
        else q' `creditWith` 1
      deep (measure (z, w) <> 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 q = do
  tick
  case q of
    Empty -> pure Empty
    Single _ -> pure Empty
    Deep vq (Three _ x y) q u -> do
      deep vq (Two x y) q u
    Deep vq (Two _ x) q u -> do
      q `creditWith` 1
      deep vq (One x) q u
    Deep _ (One _) q u -> do
      when (isTwo u) $ q `creditWith` 1
      force q >>= (`deep0` u)

deep0 :: (MonadCredit m, Measured a v)
      => FingerTree v (Tuple v a) m -> Digit a
      -> m (FingerTree v a m)
deep0 Empty u = toTree $ toList u
deep0 q u = do
  hd <- head q
  case hd of
    Pair _ x y -> do
      t <- delay $ FTail q
      unless (isTwo u) $ t `creditWith` 1
      let v = measureTail q
      deep v (Two x y) t u
    Triple _ x _ _ -> do
      let q' = map1 chop q
      q'' <- value q'
      deep (measure q') (One x) q'' u
  where chop (Triple _ _ y z) = pair y z

map1 :: (Measured a v) => (a -> a)
     -> FingerTree v a m -> FingerTree v a m
map1 f q = case q of
  Empty -> Empty
  Single x -> Single (f x)
  Deep v (One x)       m sf -> Deep v (One (f x))       m sf
  Deep v (Two x y)     m sf -> Deep v (Two (f x) y)     m sf
  Deep v (Three x y z) m sf -> Deep v (Three (f x) y z) m sf

measureTail :: Measured a v
            => FingerTree v (Tuple v a) m -> v
measureTail q = case q of
  Empty -> mempty
  Single _ -> mempty
  Deep v pr _ sf -> case pr of
    One _       ->                   v <> measure sf
    Two _ y     -> measure y      <> v <> measure sf
    Three _ y z -> measure (y, z) <> v <> measure sf

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] -> 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' (measure m'') (Two x y) (value m'') sf
    Just (Triple _ x y z, m'') -> do
      deep' (measure m'') (Three x y z) (value 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 w = do
  tick
  case q of
    Empty -> pure $ Single w
    Single x -> do
      em <- value Empty
      deep mempty (One x) em (One w)
    Deep v front middle (One x) ->
      deep v front middle (Two x w)
    Deep v front middle (Two x y) -> do
      middle `creditWith` 1
      deep v front middle (Three x y w)
    Deep v front middle (Three x y z) -> do
      t <- delay $ FSnoc middle (pair x y)
      if isTwo front
        then middle `creditWith` 1
        else t      `creditWith` 1
      deep (v <> measure (x, y)) front t (Two z w)

init :: (MonadCredit m, Measured a v) => FingerTree v a m -> m (FingerTree v a m)
init q = do
  tick
  case q of
    Empty -> pure Empty
    Single _ -> pure Empty
    Deep vq f q (Three x y _) -> do
      deep vq f q (Two x y)
    Deep vq f q (Two x _) -> do
      q `creditWith` 1
      deep vq f q (One x)
    Deep _ f q (One _) -> do
      when (isTwo f) $
        q `creditWith` 1
      deepN f =<< force q

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 s (Single (Pair _ x y)) = do
  deep' mempty s empty (Two x y)
deepN s (Single (Triple _ x y z)) = do
  deep' (measure x <> measure y) s (value (Single (pair x y))) (One z)
deepN u (Deep vq pr q sf) = do
  case chopN sf of
    Left (vsf', x, y) -> do
      t <- delay $ FInit (Deep vq pr q sf)
      unless (isTwo u) $ creditWith t 1
      deep (measure pr <> vq <> vsf') u t (Two x y)
    Right (sf', x) -> do
      deep' (measure pr <> vq <> measure sf') u (value (Deep vq pr q sf')) (One x)

chopN :: (Measured a v) => Digit (Tuple v a) -> Either (v, a, a) (Digit (Tuple v a), a)
chopN (One (Pair _ x y)) = Left (mempty, x, y)
chopN (Two x (Pair _ y z)) = Left (measure x, y, z)
chopN (Three x y (Pair _ z w)) = Left (measure x <> measure y, z, w)
chopN (One (Triple _ x y z)) = Right (One (pair x y), z)
chopN (Two x (Triple _ y z w)) = Right (Two x (pair y z), w)
chopN (Three x y (Triple _ z w u)) = Right (Three x y (pair z w), u)

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 -> 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' (measure m'') s (value m'') (Two x y)
    Just (m'', Triple _ x y z) -> do
      deep' (measure m'') s (value 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' (measure q) u1 (value 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
  { 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, [])

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 Empty x Empty
splitTree p i (Deep vm pr m sf) = do
  tick
  m `creditWith` 2
  let vpr = i <> measure pr
  let vprm = vpr <> vm
  if p vpr then do
    let (l, x, r) = splitDigit p i pr
    Split <$> toTree l <*> pure x <*> deepL r vm m sf
  else if p vprm then do
    Split ml xs mr <- splitTree p vpr =<< force m
    let vml = measure ml
    let (l, x, r) = splitDigit p (vpr <> vml) (toDigit xs)
    [ml', mr'] <- mapM value [ml, mr]
    Split <$> deepR pr vml ml' l <*> pure x <*> deepL r (measure mr) mr' sf
  else do
    let (l, x, r) = splitDigit p vprm sf
    Split <$> 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
  if p (measure xs)
    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
  (Split l x _) <- splitTree p i t
  let ml = measure l
  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 (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)

len :: MonadCredit m => FingerRA a m -> Size
len (FingerRA t) = measure 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
    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
    Split l (Elem x) r <- splitTree (fromIntegral i <) 0 xs
    if fromIntegral i > len (FingerRA l)
      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
    (Split l (Elem x) r) <- splitTree (measure xs >=) 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 Eq a => 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