List-0.4.0: src/Control/Monad/ListT.hs
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, StandaloneDeriving, TypeFamilies, UndecidableInstances #-}
-- Module is called ListT because List is taken by mtl
-- | A list monad transformer / a monadic list.
--
-- Monadic list example:
-- A program which reads numbers from the user and accumulates them.
--
-- > import Control.Monad (join)
-- > import Control.Monad.ListT (ListT)
-- > import Control.Monad.Trans (lift)
-- > import Data.List.Class (execute, repeat, scanl, takeWhile, mapL)
-- > import Prelude hiding (repeat, scanl, takeWhile)
-- >
-- > main =
-- > execute . mapL print .
-- > scanl (+) 0 .
-- > fmap (fst . head) .
-- > takeWhile (not . null) .
-- > fmap reads $ do
-- > repeat ()
-- > lift getLine :: ListT IO String
module Control.Monad.ListT (ListT(..)) where
import Data.List.Class (List(..), ListItem(..), foldrL)
import Control.Applicative (Applicative(..))
import Control.Monad (MonadPlus(..), ap, liftM)
import Control.Monad.IO.Class (MonadIO(..))
import Control.Monad.Trans.Class (MonadTrans(..))
import Data.Monoid (Monoid(..))
newtype ListT m a =
ListT { runListT :: m (ListItem (ListT m) a) }
deriving instance (Eq (m (ListItem (ListT m) a))) => Eq (ListT m a)
deriving instance (Ord (m (ListItem (ListT m) a))) => Ord (ListT m a)
deriving instance (Read (m (ListItem (ListT m) a))) => Read (ListT m a)
deriving instance (Show (m (ListItem (ListT m) a))) => Show (ListT m a)
-- for mappend, fmap, bind
foldrL' :: List l => (a -> l b -> l b) -> l b -> l a -> l b
foldrL' consFunc nilFunc =
joinL . foldrL step (return nilFunc)
where
step x = return . consFunc x . joinL
-- like generic cons except using that one
-- would cause an infinite loop
cons :: Monad m => a -> ListT m a -> ListT m a
cons x = ListT . return . Cons x
instance Monad m => Monoid (ListT m a) where
mempty = ListT $ return Nil
mappend = flip (foldrL' cons)
instance Monad m => Functor (ListT m) where
fmap func = foldrL' (cons . func) mempty
instance Monad m => Monad (ListT m) where
return = ListT . return . (`Cons` mempty)
a >>= b = foldrL' mappend mempty (fmap b a)
instance Monad m => Applicative (ListT m) where
pure = return
(<*>) = ap
instance Monad m => MonadPlus (ListT m) where
mzero = mempty
mplus = mappend
instance MonadTrans ListT where
lift = ListT . liftM (`Cons` mempty)
instance Monad m => List (ListT m) where
type ItemM (ListT m) = m
runList = runListT
joinL = ListT . (>>= runList)
instance MonadIO m => MonadIO (ListT m) where
liftIO = lift . liftIO