packages feed

free-listt-0.1.0.0: src/Control/Monad/Trans/List.hs

-- | Free list monad transformer
module Control.Monad.Trans.List where

-- base
import Control.Applicative
import Control.Monad
import Control.Monad.IO.Class
import Data.Functor.Classes

-- transformers
import Control.Monad.Trans.Class

-- mtl
import Control.Monad.Error.Class
import Control.Monad.RWS (MonadRWS, MonadReader, MonadState)
import Control.Monad.Writer

-- exceptions
import Control.Monad.Catch (MonadCatch, MonadThrow)

-- free
import Control.Monad.Trans.Free

-- free-listt
import Control.Applicative.Trans.List qualified as Applicative

{- | The free list monad transformer.

It is implemented as a rose tree (see https://en.wikipedia.org/wiki/Rose_tree)
of computations in @m@.
-}
newtype ListT m a = ListT {getListT :: FreeT [] m a}
  deriving
    ( Functor
    , Applicative
    , Monad
    , Alternative
    , MonadPlus
    , MonadIO
    , MonadFail
    , MonadTrans
    , Eq1
    , Ord1
    , Read1
    , Show1
    , Eq
    , Ord
    , Read
    , Show
    , MonadError e
    , MonadState s
    , MonadReader r
    , MonadRWS r w s
    , MonadWriter w
    , MonadCatch
    , MonadThrow
    )

-- | Flatten all layers of computations to a single one.
flatten :: (Monad m) => ListT m a -> Applicative.ListT m a
flatten = Applicative.ListT . runListT

-- | Like 'flatten', but remove the 'Applicative.ListT' wrapper.
runListT :: (Monad m) => ListT m a -> m [a]
runListT = iterT (fmap concat . sequence) . fmap pure . getListT

-- | Construct a 'ListT' from an effectful list (a single layer).
listT :: (Monad m) => m [a] -> ListT m a
listT = ListT . FreeT . fmap (Free . fmap pure)

-- | Construct a 'ListT' from a single effectful value.
singleton :: (Functor m) => m a -> ListT m a
singleton = ListT . FreeT . fmap Pure