module Data.Cond
( CondT(..), Cond
, runCondT, applyCondT, runCond, applyCond
, guardM, guard_, guardM_, apply, consider
, matches, if_, when_, unless_, or_, and_, not_
, ignore, norecurse, prune
, test, recurse
) where
import Control.Applicative
import Control.Arrow (first)
import Control.Monad hiding (mapM_, sequence_)
import Control.Monad.Base
import Control.Monad.Catch
import Control.Monad.Morph
import Control.Monad.Reader.Class
import Control.Monad.State.Class
import Control.Monad.Trans
import Control.Monad.Trans.Control
import Control.Monad.Trans.State (StateT(..), withStateT, evalStateT)
import Data.Foldable
import Data.Functor.Identity
import Data.Maybe (fromMaybe, isJust)
import Data.Monoid hiding ((<>))
import Data.Semigroup
import Prelude hiding (mapM_, foldr1, sequence_)
data Result a m b = Ignore
| Keep b
| RecurseOnly (Maybe (CondT a m b))
| KeepAndRecurse b (Maybe (CondT a m b))
instance Show b => Show (Result a m b) where
show Ignore = "Ignore"
show (Keep a) = "Keep " ++ show a
show (RecurseOnly _) = "RecurseOnly"
show (KeepAndRecurse a _) = "KeepAndRecurse " ++ show a
instance Monad m => Functor (Result a m) where
fmap _ Ignore = Ignore
fmap f (Keep a) = Keep (f a)
fmap f (RecurseOnly l) = RecurseOnly (liftM (fmap f) l)
fmap f (KeepAndRecurse a l) = KeepAndRecurse (f a) (liftM (fmap f) l)
instance MFunctor (Result a) where
hoist _ Ignore = Ignore
hoist _ (Keep a) = Keep a
hoist nat (RecurseOnly l) = RecurseOnly (fmap (hoist nat) l)
hoist nat (KeepAndRecurse a l) = KeepAndRecurse a (fmap (hoist nat) l)
instance Semigroup (Result a m b) where
Ignore <> _ = Ignore
_ <> Ignore = Ignore
RecurseOnly _ <> Keep _ = Ignore
RecurseOnly _ <> KeepAndRecurse _ m = RecurseOnly m
RecurseOnly m <> _ = RecurseOnly m
Keep _ <> RecurseOnly _ = Ignore
_ <> RecurseOnly m = RecurseOnly m
_ <> Keep b = Keep b
Keep _ <> KeepAndRecurse b _ = Keep b
_ <> KeepAndRecurse b m = KeepAndRecurse b m
instance Monoid b => Monoid (Result a m b) where
mempty = KeepAndRecurse mempty Nothing
mappend = (<>)
accept' :: b -> Result a m b
accept' = flip KeepAndRecurse Nothing
recurse' :: Result a m b
recurse' = RecurseOnly Nothing
toResult :: Monad m => Maybe a -> forall r. Result r m a
toResult Nothing = recurse'
toResult (Just a) = accept' a
fromResult :: Monad m => forall r. Result r m a -> Maybe a
fromResult Ignore = Nothing
fromResult (Keep a) = Just a
fromResult (RecurseOnly _) = Nothing
fromResult (KeepAndRecurse a _) = Just a
newtype CondT a m b = CondT { getCondT :: StateT a m (Result a m b) }
type Cond a = CondT a Identity
instance (Monad m, Semigroup b) => Semigroup (CondT a m b) where
(<>) = liftM2 (<>)
instance (Monad m, Monoid b) => Monoid (CondT a m b) where
mempty = CondT $ return $ accept' mempty
mappend = liftM2 mappend
instance Monad m => Functor (CondT a m) where
fmap f (CondT g) = CondT (liftM (fmap f) g)
instance Monad m => Applicative (CondT a m) where
pure = return
(<*>) = ap
instance Monad m => Monad (CondT a m) where
return = CondT . return . accept'
fail _ = mzero
CondT f >>= k = CondT $ do
r <- f
case r of
Ignore -> return Ignore
Keep b -> do
n <- getCondT (k b)
return $ case n of
RecurseOnly _ -> Ignore
KeepAndRecurse c _ -> Keep c
_ -> n
RecurseOnly l -> return $ RecurseOnly (fmap (>>= k) l)
KeepAndRecurse b _ -> getCondT (k b)
instance Monad m => MonadReader a (CondT a m) where
ask = CondT $ gets accept'
local f (CondT m) = CondT $ withStateT f m
reader f = liftM f ask
instance Monad m => MonadState a (CondT a m) where
get = CondT $ gets accept'
put s = CondT $ liftM accept' $ put s
state f = CondT $ state (fmap (first accept') f)
instance Monad m => Alternative (CondT a m) where
empty = CondT $ return recurse'
CondT f <|> CondT g = CondT $ do
r <- f
case r of
x@(Keep _) -> return x
x@(KeepAndRecurse _ _) -> return x
_ -> g
instance Monad m => MonadPlus (CondT a m) where
mzero = empty
mplus = (<|>)
instance MonadThrow m => MonadThrow (CondT a m) where
throwM = CondT . throwM
instance MonadCatch m => MonadCatch (CondT a m) where
catch (CondT m) c = CondT $ m `catch` \e -> getCondT (c e)
mask a = CondT $ mask $ \u -> getCondT (a $ q u)
where q u = CondT . u . getCondT
uninterruptibleMask a =
CondT $ uninterruptibleMask $ \u -> getCondT (a $ q u)
where q u = CondT . u . getCondT
instance MonadBase b m => MonadBase b (CondT a m) where
liftBase m = CondT $ liftM accept' $ liftBase m
instance MonadIO m => MonadIO (CondT a m) where
liftIO m = CondT $ liftM accept' $ liftIO m
instance MonadTrans (CondT a) where
lift m = CondT $ liftM accept' $ lift m
instance MonadBaseControl b m => MonadBaseControl b (CondT r m) where
newtype StM (CondT r m) a =
CondTStM { unCondTStM :: StM m (Result r m a, r) }
liftBaseWith f = CondT $ StateT $ \s ->
liftM (\x -> (accept' x, s)) $ liftBaseWith $ \runInBase -> f $ \k ->
liftM CondTStM $ runInBase $ runStateT (getCondT k) s
restoreM = CondT . StateT . const . restoreM . unCondTStM
instance MFunctor (CondT a) where
hoist nat (CondT m) = CondT $ hoist nat (liftM (hoist nat) m)
runCondT :: Monad m => CondT a m b -> a -> m (Maybe b)
runCondT (CondT f) a = fromResult `liftM` evalStateT f a
runCond :: Cond a b -> a -> Maybe b
runCond = (runIdentity .) . runCondT
applyCondT :: Monad m
=> a
-> CondT a m b
-> (a -> Maybe b -> Maybe (CondT a m b) -> m ())
-> m ()
applyCondT a c k = do
(r, a') <- runStateT (getCondT c) a
case r of
Ignore -> k a' Nothing Nothing
Keep b -> k a' (Just b) Nothing
RecurseOnly c' -> k a' Nothing (Just (fromMaybe c c'))
KeepAndRecurse b c' -> k a' (Just b) (Just (fromMaybe c c'))
applyCond :: Monoid c
=> a
-> Cond a b
-> (a -> Maybe b -> Maybe (Cond a b) -> c)
-> c
applyCond a c k = case runIdentity (runStateT (getCondT c) a) of
(Ignore, a') -> k a' Nothing Nothing
(Keep b, a') -> k a' (Just b) Nothing
(RecurseOnly c', a') -> k a' Nothing (Just (fromMaybe c c'))
(KeepAndRecurse b c', a') -> k a' (Just b) (Just (fromMaybe c c'))
guardM :: Monad m => m Bool -> CondT a m ()
guardM m = lift m >>= guard
guard_ :: Monad m => (a -> Bool) -> CondT a m ()
guard_ f = ask >>= guard . f
guardM_ :: Monad m => (a -> m Bool) -> CondT a m ()
guardM_ f = ask >>= lift . f >>= guard
apply :: Monad m => (a -> m (Maybe b)) -> CondT a m b
apply f = CondT $ get >>= liftM toResult . lift . f
consider :: Monad m => (a -> m (Maybe (b, a))) -> CondT a m b
consider f = CondT $ do
a <- get
mres <- lift $ f a
case mres of
Nothing -> return Ignore
Just (b, a') -> put a' >> return (accept' b)
matches :: Monad m => CondT a m b -> CondT a m Bool
matches = fmap isJust . optional
if_ :: Monad m => CondT a m b -> CondT a m c -> CondT a m c -> CondT a m c
if_ c x y = CondT $ do
r <- getCondT c
getCondT $ case r of
Ignore -> y
Keep _ -> x
RecurseOnly _ -> y
KeepAndRecurse _ _ -> x
when_ :: Monad m => CondT a m b -> CondT a m () -> CondT a m ()
when_ c x = if_ c x (return ())
unless_ :: Monad m => CondT a m b -> CondT a m () -> CondT a m ()
unless_ c = if_ c (return ())
or_ :: Monad m => [CondT a m b] -> CondT a m b
or_ = asum
and_ :: Monad m => [CondT a m b] -> CondT a m ()
and_ = sequence_
not_ :: Monad m => CondT a m b -> CondT a m ()
not_ c = when_ c ignore
ignore :: Monad m => CondT a m b
ignore = mzero
prune :: Monad m => CondT a m ()
prune = CondT $ return Ignore
norecurse :: Monad m => CondT a m ()
norecurse = CondT $ return $ Keep ()
test :: Monad m => CondT a m b -> a -> m Bool
test = (liftM isJust .) . runCondT
recurse :: Monad m => CondT a m b -> CondT a m b
recurse c = CondT $ do
r <- getCondT c
return $ case r of
Ignore -> Ignore
Keep b -> Keep b
RecurseOnly _ -> RecurseOnly (Just c)
KeepAndRecurse b _ -> KeepAndRecurse b (Just c)