monoid-subclasses-1.2.4: src/Data/Monoid/Instances/PrefixMemory.hs
{-
Copyright 2023 Mario Blazevic
License: BSD3 (see BSD3-LICENSE.txt file)
-}
-- | This module defines the monoid transformer data type 'Shadowed'.
{-# LANGUAGE Haskell2010, DeriveDataTypeable #-}
module Data.Monoid.Instances.PrefixMemory (
Shadowed, shadowed, content, prefix
)
where
import Control.Applicative -- (Applicative(..))
import qualified Data.List as List
import Data.String (IsString(fromString))
import Data.Data (Data, Typeable)
import Data.Semigroup (Semigroup(..))
import Data.Monoid (Monoid(..), Endo(..))
import Data.Semigroup.Cancellative (LeftReductive(..), RightReductive(..))
import Data.Semigroup.Factorial (Factorial(..), StableFactorial)
import Data.Monoid.GCD (LeftGCDMonoid(..), RightGCDMonoid(..))
import Data.Monoid.Null (MonoidNull(null), PositiveMonoid)
import Data.Monoid.Factorial (FactorialMonoid(..))
import Data.Monoid.Textual (TextualMonoid(..))
import qualified Data.Semigroup.Factorial as Factorial
import qualified Data.Monoid.Factorial as Factorial
import qualified Data.Monoid.Textual as Textual
import Prelude hiding (all, any, break, filter, foldl, foldl1, foldr, foldr1, lines, map, concatMap,
length, null, reverse, scanl, scanr, scanl1, scanr1, span, splitAt)
-- | Monoid transformer that keeps track of the former 'prefix' of its 'content'. All functions that return a suffix
-- of their argument, such as 'stripPrefix' or 'commonSuffix', preserve the discarded 'prefix'.
data Shadowed m = Shadowed{prefix :: !m,
-- ^ used to precede the 'content' but has been consumed
content :: !m
-- ^ the present value
} deriving (Data, Typeable)
-- | The constructor of a 'Shadowed' monoid, with the initial @prefix = null@
shadowed :: Monoid m => m -> Shadowed m
shadowed = Shadowed mempty
instance Eq m => Eq (Shadowed m) where
Shadowed{content = a} == Shadowed{content = b} = a == b
instance Ord m => Ord (Shadowed m) where
compare Shadowed{content= a} Shadowed{content= b} = compare a b
instance (MonoidNull m, Show m) => Show (Shadowed m) where
showsPrec prec (Shadowed p c) rest
| null p = showsPrec prec c rest
| otherwise = "Shadowed{prefix=" <> shows p (", content=" <> shows c ("}" <> rest))
instance (MonoidNull m, StableFactorial m) => Semigroup (Shadowed m) where
Shadowed p1 c1 <> m2@Shadowed{content = c2}
| null c1 && null p1 = m2
| otherwise = Shadowed p1 (c1 <> c2)
{-# INLINE (<>) #-}
instance (MonoidNull m, StableFactorial m) => Monoid (Shadowed m) where
mempty = shadowed mempty
mappend = (<>)
{-# INLINE mempty #-}
{-# INLINE mappend #-}
instance (MonoidNull m, StableFactorial m) => MonoidNull (Shadowed m) where
null = null . content
{-# INLINE null #-}
instance (PositiveMonoid m, StableFactorial m) => PositiveMonoid (Shadowed m)
instance (MonoidNull m, StableFactorial m, LeftReductive m) => LeftReductive (Shadowed m) where
t1 `isPrefixOf` t2 = content t1 `isPrefixOf` content t2
stripPrefix (Shadowed _ c1) (Shadowed p c2) = fmap (Shadowed (p <> c1)) (stripPrefix c1 c2)
{-# INLINE isPrefixOf #-}
{-# INLINE stripPrefix #-}
instance (Eq m, StableFactorial m, FactorialMonoid m, LeftGCDMonoid m) => LeftGCDMonoid (Shadowed m) where
stripCommonPrefix (Shadowed p1 c1) (Shadowed p2 c2) =
(Shadowed prefix' common, Shadowed (p1 <> common) c1', Shadowed (p2 <> common) c2')
where (common, c1', c2') = stripCommonPrefix c1 c2
prefix' = if p1 == p2 then p1 <> common else common
{-# INLINE stripCommonPrefix #-}
instance (StableFactorial m, FactorialMonoid m, RightReductive m) => RightReductive (Shadowed m) where
isSuffixOf (Shadowed _ c1) (Shadowed _ c2) = isSuffixOf c1 c2
stripSuffix (Shadowed _ c1) (Shadowed p c2) = fmap (Shadowed p) (stripSuffix c1 c2)
{-# INLINE isSuffixOf #-}
{-# INLINE stripSuffix #-}
instance (StableFactorial m, FactorialMonoid m, RightGCDMonoid m) => RightGCDMonoid (Shadowed m) where
commonSuffix (Shadowed _ c1) (Shadowed _ c2) = shadowed suffix
where suffix = commonSuffix c1 c2
stripCommonSuffix (Shadowed p1 c1) (Shadowed p2 c2) =
(Shadowed p1 c1', Shadowed p2 c2',
shadowed suffix)
where (c1', c2', suffix) = stripCommonSuffix c1 c2
{-# INLINE commonSuffix #-}
{-# INLINE stripCommonSuffix #-}
instance (FactorialMonoid m, StableFactorial m) => Factorial (Shadowed m) where
factors (Shadowed p c) = rewrap <$> List.tail (inits c)
where rewrap t
| Just (p', prime) <- splitPrimeSuffix t = Shadowed (p <> p') prime
| otherwise = error "all (not . null) . tail . inits"
primePrefix (Shadowed p c) = Shadowed p (primePrefix c)
foldl f a0 (Shadowed p0 c0) = fst $ Factorial.foldl f' (a0, p0) c0
where f' (a, p) c = (f a (Shadowed p c), p <> c)
foldl' f a0 (Shadowed p0 c0) = fst $ Factorial.foldl' f' (a0, p0) c0
where f' (a, p) c = ((,) $! f a (Shadowed p c)) $! p <> c
foldr f a0 (Shadowed p0 c0) = Factorial.foldr f' (const a0) c0 p0
where f' c cont p = f (Shadowed p c) (cont $! p <> c)
foldMap f (Shadowed p0 c) = appEndo (Factorial.foldMap f' c) (const mempty) p0
where -- f' :: m -> Endo (Int -> m)
f' prime = Endo (\cont p-> f (Shadowed p prime) `mappend` (cont $! p <> prime))
length (Shadowed _ c) = length c
reverse (Shadowed p c) = Shadowed p (Factorial.reverse c)
{-# INLINE primePrefix #-}
{-# INLINE foldl #-}
{-# INLINE foldl' #-}
{-# INLINE foldr #-}
{-# INLINE foldMap #-}
instance (StableFactorial m, FactorialMonoid m) => FactorialMonoid (Shadowed m) where
splitPrimePrefix (Shadowed p c) = fmap rewrap (splitPrimePrefix c)
where rewrap (cp, cs) = (Shadowed p cp, Shadowed (p <> cp) cs)
splitPrimeSuffix (Shadowed p c) = fmap rewrap (splitPrimeSuffix c)
where rewrap (cp, cs) = (Shadowed p cp, Shadowed (p <> cp) cs)
spanMaybe s0 f (Shadowed p0 c) = rewrap $ Factorial.spanMaybe (s0, p0) f' c
where f' (s, p) prime = do s' <- f s (Shadowed p prime)
let p' = p <> prime
Just $! seq p' (s', p')
rewrap (cp, cs, (s, p)) = (Shadowed p0 cp, Shadowed p cs, s)
spanMaybe' s0 f (Shadowed p0 c) = rewrap $! Factorial.spanMaybe' (s0, p0) f' c
where f' (s, p) prime = do s' <- f s (Shadowed p prime)
let p' = p <> prime
Just $! s' `seq` p' `seq` (s', p')
rewrap (cp, cs, (s, p)) = (Shadowed p0 cp, Shadowed p cs, s)
span f (Shadowed p0 c) = rewrap $ Factorial.spanMaybe' p0 f' c
where f' p prime = if f (Shadowed p prime)
then Just $! p <> prime
else Nothing
rewrap (cp, cs, p) = (Shadowed p0 cp, Shadowed p cs)
splitAt n (Shadowed p c) = (Shadowed p cp, Shadowed (p <> cp) cs)
where (cp, cs) = splitAt n c
take n (Shadowed p c) = Shadowed p (Factorial.take n c)
{-# INLINE splitPrimePrefix #-}
{-# INLINE splitPrimeSuffix #-}
{-# INLINE span #-}
{-# INLINE splitAt #-}
{-# INLINE take #-}
instance (StableFactorial m, FactorialMonoid m) => StableFactorial (Shadowed m)
instance (Monoid m, IsString m) => IsString (Shadowed m) where
fromString = shadowed . fromString
instance (Eq m, StableFactorial m, TextualMonoid m) => TextualMonoid (Shadowed m) where
splitCharacterPrefix (Shadowed p t) = (Shadowed p <$>) <$> Textual.splitCharacterPrefix t
fromText = shadowed . fromText
singleton = shadowed . singleton
characterPrefix = characterPrefix . content
map f (Shadowed p c) = Shadowed p (map f c)
concatMap f (Shadowed p c) = Shadowed p (concatMap (content . f) c)
all p = all p . content
any p = any p . content
foldl ft fc a0 (Shadowed p0 c0) = fst $ Textual.foldl ft' fc' (a0, p0) c0
where ft' (a, p) c = (ft a (Shadowed p c), p <> c)
fc' (a, p) c = (fc a c, p <> Textual.singleton c)
foldl' ft fc a0 (Shadowed p0 c0) = fst $ Textual.foldl' ft' fc' (a0, p0) c0
where ft' (a, p) c = ((,) $! ft a (Shadowed p c)) $! p <> c
fc' (a, p) c = ((,) $! fc a c) $! p <> Textual.singleton c
foldr ft fc a0 (Shadowed p0 c0) = snd $ Textual.foldr ft' fc' (p0, a0) c0
where ft' c (p, a) = ((,) $! p <> c) $! ft (Shadowed p c) a
fc' c (p, a) = ((,) $! p <> Textual.singleton c) $! fc c a
scanl f ch (Shadowed p c) = Shadowed p (Textual.scanl f ch c)
scanl1 f (Shadowed p c) = Shadowed p (Textual.scanl1 f c)
scanr f ch (Shadowed p c) = Shadowed p (Textual.scanr f ch c)
scanr1 f (Shadowed p c) = Shadowed p (Textual.scanr1 f c)
mapAccumL f a0 (Shadowed p c) = fmap (Shadowed p) (Textual.mapAccumL f a0 c)
mapAccumR f a0 (Shadowed p c) = fmap (Shadowed p) (Textual.mapAccumR f a0 c)
spanMaybe s0 ft fc (Shadowed p0 t) = rewrap $ Textual.spanMaybe (s0, p0) ft' fc' t
where ft' (s, p) prime = do s' <- ft s (Shadowed p prime)
let p' = p <> prime
Just $! seq p' (s', p')
fc' (s, p) c = do s' <- fc s c
let p' = p <> Textual.singleton c
Just $! seq p' (s', p')
rewrap (tp, ts, (s, p)) = (Shadowed p0 tp, Shadowed p ts, s)
spanMaybe' s0 ft fc (Shadowed p0 t) = rewrap $! Textual.spanMaybe' (s0, p0) ft' fc' t
where ft' (s, p) prime = do s' <- ft s (Shadowed p prime)
let p' = p <> prime
Just $! s' `seq` p' `seq` (s', p')
fc' (s, p) c = do s' <- fc s c
let p' = p <> Textual.singleton c
Just $! s' `seq` p' `seq` (s', p')
rewrap (tp, ts, (s, p)) = (Shadowed p0 tp, Shadowed p ts, s)
span ft fc (Shadowed p0 t) = rewrap $ Textual.spanMaybe' p0 ft' fc' t
where ft' p prime = if ft (Shadowed p prime)
then Just $! p <> prime
else Nothing
fc' p c = if fc c
then Just $! p <> Textual.singleton c
else Nothing
rewrap (tp, ts, p) = (Shadowed p0 tp, Shadowed p ts)
split f (Shadowed p0 c0) = rewrap p0 (Textual.split f c0)
where rewrap _ [] = []
rewrap p (c:rest) = Shadowed p c : rewrap (p <> c) rest
find p = find p . content
foldl_ fc a0 (Shadowed _ c) = Textual.foldl_ fc a0 c
foldl_' fc a0 (Shadowed _ c) = Textual.foldl_' fc a0 c
foldr_ fc a0 (Shadowed _ c) = Textual.foldr_ fc a0 c
spanMaybe_ s0 fc (Shadowed p0 t) = rewrap $ Textual.spanMaybe_' (s0, p0) fc' t
where fc' (s, p) c = do s' <- fc s c
let p' = p <> Textual.singleton c
Just $! seq p' (s', p')
rewrap (tp, ts, (s, p)) = (Shadowed p0 tp, Shadowed p ts, s)
spanMaybe_' s0 fc (Shadowed p0 t) = rewrap $! Textual.spanMaybe_' (s0, p0) fc' t
where fc' (s, p) c = do s' <- fc s c
let p' = p <> Textual.singleton c
Just $! s' `seq` p' `seq` (s', p')
rewrap (tp, ts, (s, p)) = (Shadowed p0 tp, Shadowed p ts, s)
span_ bt fc (Shadowed p0 t) = rewrap $ Textual.span_ bt fc t
where rewrap (tp, ts) = (Shadowed p0 tp, Shadowed (p0 <> tp) ts)
break_ bt fc (Shadowed p0 t) = rewrap $ Textual.break_ bt fc t
where rewrap (tp, ts) = (Shadowed p0 tp, Shadowed (p0 <> tp) ts)
dropWhile_ bt fc t = snd (span_ bt fc t)
takeWhile_ bt fc (Shadowed p t) = Shadowed p (takeWhile_ bt fc t)
toString ft (Shadowed _ t) = toString (ft . shadowed) t
toText ft (Shadowed _ t) = toText (ft . shadowed) t
{-# INLINE characterPrefix #-}
{-# INLINE splitCharacterPrefix #-}
{-# INLINE map #-}
{-# INLINE concatMap #-}
{-# INLINE foldl' #-}
{-# INLINE foldr #-}
{-# INLINABLE spanMaybe #-}
{-# INLINABLE spanMaybe' #-}
{-# INLINABLE span #-}
{-# INLINE foldl_' #-}
{-# INLINE foldr_ #-}
{-# INLINE any #-}
{-# INLINE all #-}
{-# INLINABLE spanMaybe_ #-}
{-# INLINABLE spanMaybe_' #-}
{-# INLINE span_ #-}
{-# INLINE break_ #-}
{-# INLINE dropWhile_ #-}
{-# INLINE takeWhile_ #-}
{-# INLINE split #-}
{-# INLINE find #-}