module ListT
(
ListT,
MonadTransUncons(..),
MonadCons(..),
head,
tail,
null,
fold,
foldMaybe,
toList,
toReverseList,
traverse_,
splitAt,
fromFoldable,
fromMVar,
unfold,
repeat,
Transformation,
traverse,
take,
drop,
slice,
Positive,
positive,
)
where
import BasePrelude hiding (uncons, toList, yield, fold, traverse, head, tail, take, drop, repeat, null, traverse_, splitAt)
import Control.Monad.Morph hiding (MonadTrans(..))
import Control.Monad.IO.Class
import Control.Monad.Error.Class
import Control.Monad.Trans.Class
import Control.Monad.Trans.Reader
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.Control hiding (embed, embed_)
import Control.Monad.Base
newtype ListT m a =
ListT { unListT :: m (Maybe (a, ListT m a)) }
instance Monad m => Monoid (ListT m a) where
mempty =
ListT $
return Nothing
mappend (ListT m1) (ListT m2) =
ListT $
m1 >>=
\case
Nothing ->
m2
Just (h1, s1') ->
return (Just (h1, (mappend s1' (ListT m2))))
instance Functor m => Functor (ListT m) where
fmap f (ListT m) =
ListT $ (fmap . fmap) (\(a, b) -> (f a, fmap f b)) m
instance (Monad m, Functor m) => Applicative (ListT m) where
pure =
return
(<*>) =
ap
instance (Monad m, Functor m) => Alternative (ListT m) where
empty =
inline mzero
(<|>) =
inline mplus
instance Monad m => Monad (ListT m) where
return a =
ListT $ return (Just (a, (ListT (return Nothing))))
(>>=) s1 k2 =
ListT $
uncons s1 >>=
\case
Nothing ->
return Nothing
Just (h1, t1) ->
uncons $ k2 h1 <> (t1 >>= k2)
instance Monad m => MonadPlus (ListT m) where
mzero =
inline mempty
mplus =
inline mappend
instance MonadTrans ListT where
lift =
ListT . liftM (\a -> Just (a, mempty))
instance MonadIO m => MonadIO (ListT m) where
liftIO =
lift . liftIO
instance MFunctor ListT where
hoist f (ListT m) =
ListT $ f $ m >>= return . fmap (\(h, t) -> (h, hoist f t))
instance MMonad ListT where
embed f (ListT m) =
f m >>= \case
Nothing -> mzero
Just (h, t) -> ListT $ return $ Just $ (h, embed f t)
instance MonadBase b m => MonadBase b (ListT m) where
liftBase =
lift . liftBase
#if MIN_VERSION_monad_control(1,0,0)
instance MonadBaseControl b m => MonadBaseControl b (ListT m) where
type StM (ListT m) a =
StM m (Maybe (a, ListT m a))
liftBaseWith runToBase =
lift $ liftBaseWith $ \runInner ->
runToBase $ runInner . uncons
restoreM inner =
lift (restoreM inner) >>= \case
Nothing -> mzero
Just (h, t) -> cons h t
#else
instance MonadBaseControl b m => MonadBaseControl b (ListT m) where
newtype StM (ListT m) a =
StM (StM m (Maybe (a, ListT m a)))
liftBaseWith runToBase =
lift $ liftBaseWith $ \runInner ->
runToBase $ liftM StM . runInner . uncons
restoreM (StM inner) =
lift (restoreM inner) >>= \case
Nothing -> mzero
Just (h, t) -> cons h t
#endif
instance MonadError e m => MonadError e (ListT m) where
throwError = ListT . throwError
catchError m handler = ListT $ catchError (unListT m) $ unListT . handler
class MonadTrans t => MonadTransUncons t where
uncons :: Monad m => t m a -> m (Maybe (a, t m a))
instance MonadTransUncons ListT where
uncons (ListT m) = m
class MonadPlus m => MonadCons m where
cons :: a -> m a -> m a
instance MonadCons [] where
cons a m = a : m
instance Monad m => MonadCons (ListT m) where
cons h t = ListT $ return (Just (h, t))
instance MonadCons m => MonadCons (ReaderT e m) where
cons a m = ReaderT $ cons a . runReaderT m
head :: (Monad m, MonadTransUncons t) => t m a -> m (Maybe a)
head =
liftM (fmap fst) . uncons
tail :: (Monad m, MonadTransUncons t) => t m a -> m (Maybe (t m a))
tail =
liftM (fmap snd) . uncons
null :: (Monad m, MonadTransUncons t) => t m a -> m Bool
null =
liftM (maybe True (const False)) . uncons
fold :: (Monad m, MonadTransUncons t) => (r -> a -> m r) -> r -> t m a -> m r
fold s r =
uncons >=> maybe (return r) (\(h, t) -> s r h >>= \r' -> fold s r' t)
foldMaybe :: (Monad m, MonadTransUncons t) => (r -> a -> m (Maybe r)) -> r -> t m a -> m r
foldMaybe s r l =
liftM (maybe r id) $ runMaybeT $ do
(h, t) <- MaybeT $ uncons l
r' <- MaybeT $ s r h
lift $ foldMaybe s r' t
toList :: (Monad m, MonadTransUncons t) => t m a -> m [a]
toList =
liftM ($ []) . fold (\f e -> return $ f . (e :)) id
toReverseList :: (Monad m, MonadTransUncons t) => t m a -> m [a]
toReverseList =
ListT.fold (\l -> return . (:l)) []
traverse_ :: (Monad m, MonadTransUncons t) => (a -> m ()) -> t m a -> m ()
traverse_ f =
fold (const f) ()
splitAt :: (Monad m, MonadTransUncons t, MonadPlus (t m)) => Int -> t m a -> m ([a], t m a)
splitAt =
\case
n | n > 0 -> \l ->
uncons l >>= \case
Nothing -> return ([], mzero)
Just (h, t) -> do
(r1, r2) <- splitAt (pred n) t
return (h : r1, r2)
_ -> \l ->
return ([], l)
fromFoldable :: (MonadCons m, Foldable f) => f a -> m a
fromFoldable =
foldr cons mzero
fromMVar :: (MonadCons m, MonadIO m) => MVar (Maybe a) -> m a
fromMVar v =
fix $ \loop -> liftIO (takeMVar v) >>= maybe mzero (flip cons loop)
unfold :: (MonadCons m) => (b -> Maybe (a, b)) -> b -> m a
unfold f s =
maybe mzero (\(h, t) -> cons h (unfold f t)) (f s)
repeat :: (MonadCons m) => a -> m a
repeat =
fix . cons
type Transformation m a b =
forall t. (Monad m, MonadCons (t m), MonadTransUncons t) =>
t m a -> t m b
traverse :: (a -> m b) -> Transformation m a b
traverse f s =
lift (uncons s) >>=
mapM (\(h, t) -> lift (f h) >>= \h' -> cons h' (traverse f t)) >>=
maybe mzero return
take :: Int -> Transformation m a a
take =
\case
n | n > 0 -> \t ->
lift (uncons t) >>=
\case
Nothing -> t
Just (h, t) -> cons h (take (pred n) t)
_ ->
const $ mzero
drop :: Int -> Transformation m a a
drop =
\case
n | n > 0 ->
lift . uncons >=> maybe mzero (drop (pred n) . snd)
_ ->
id
slice :: Positive Int -> Transformation m a [a]
slice n l =
do
(h, t) <- lift $ splitAt (case n of Positive n -> n) l
case h of
[] -> mzero
_ -> cons h (slice n t)
newtype Positive n =
Positive n
deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)
positive :: (Ord n, Num n) => n -> Maybe (Positive n)
positive =
\case
n | n > 0 -> Just $ Positive n
_ -> Nothing