packages feed

bytepatch-0.4.0: src/StreamPatch/Patch/Linearize/Insert.hs

module StreamPatch.Patch.Linearize.Insert where

import Control.Monad.State
import Data.List qualified as List
import StreamPatch.Util ( traverseM )

{-
-- Result seeks are non-negative, so natural-like types are safe to use.
linearizeInsert
    :: (Integral sf, Integral st)
    => [Patch sf fs a] -> Either (Error (Patch sf fs a)) [Patch st fs a]
linearizeInsert = linearize patchSeek (\s p -> p { patchSeek = s })
-}

-- | Linearize some list of @a@s.
--
-- For non-empty lists, the result is a tuple of the first @a@, followed by the
-- linearized @a@s (converted to @b@). Linearized values are non-negative, so
-- natural-like types are safe to use for @st@.
linearize
    :: (Integral sf, Integral st)
    => (a -> sf)
    -> (st -> a -> b)
    -> [a] -> Either (a, a) (Maybe (a, [b]))
linearize f g as =
    case List.sortBy cmp as of
      []      -> Right Nothing
      (a:as') -> do
        bs <- evalState (traverseM go as') a
        Right $ Just (a, bs)
  where
    cmp a1 a2 = compare (f a1) (f a2)
    go a = do
        a' <- get
        let s' = fromIntegral $ f a - f a'
        if s' == 0
        then return $ Left (a, a')
        else put a >> return (Right (g s' a))

linearize' :: (Integral sf, Integral st) => [sf] -> Either (sf, sf) (Maybe (sf, [st]))
linearize' = linearize id const