{-# LANGUAGE GeneralizedNewtypeDeriving #-} {- | Here we implement a special Reader monad that can be used to manage a call stack. This way you can generate exception messages like \"Corrupt file content encountered while reading file \'foo.txt\' while loading document \'bar.doc\'\" using the functions in "Control.Monad.Exception.Label". However, currently I believe that this datatype is unnecessary, since you can extend exceptions by context information using 'Control.Monad.Exception.Synchronous.mapException'. -} module Control.Monad.Label where import Control.Applicative (Applicative(pure, (<*>))) import Control.Monad (MonadPlus, ap, ) import Control.Monad.Fix (MonadFix) import Control.Monad.Trans (MonadTrans, MonadIO) import qualified Control.Monad.Trans.Reader as Reader import Control.Monad.Trans.Reader (Reader, ReaderT(ReaderT), runReader, runReaderT, ) import Control.Monad.Instances () -- * Plain monad newtype Label l a = Label { runLabelPriv :: Reader [l] a } -- newtype Label l a = Label { runLabelPriv :: [l] -> a } deriving (Functor, Monad, MonadFix) {- instance Functor (Label l) where fmap f m = Label $ \l -> f (runLabelPriv m l) instance Monad (Label l) where return a = Label $ \_ -> a m >>= k = Label $ \l -> runLabelPriv (k (runLabelPriv m l)) l instance MonadFix (Label l) where mfix f = Label $ \l -> let a = runLabelPriv (f a) l in a -} instance Applicative (Label l) where pure = return (<*>) = ap runLabel :: Label l a -> [l] -> a runLabel = runReader . runLabelPriv ask :: Label l [l] ask = Label Reader.ask -- ask = Label id local :: l -> Label l a -> Label l a local l m = Label $ Reader.local (l:) $ runLabelPriv m -- local l m = Label $ runLabelPriv m . (l:) -- * Monad transformer newtype LabelT l m a = LabelT { runLabelPrivT :: ReaderT [l] m a } -- newtype LabelT l m a = LabelT { runLabelPrivT :: l -> m a } deriving (Monad, MonadPlus, MonadFix, MonadTrans, MonadIO) {- instance (Monad m) => Functor (LabelT l m) where fmap f m = LabelT $ \l -> do a <- runLabelPrivT m l return (f a) instance (Monad m) => Monad (LabelT l m) where return a = LabelT $ \_ -> return a m >>= k = LabelT $ \l -> do a <- runLabelPrivT m l runLabelPrivT (k a) l fail msg = LabelT $ \_ -> fail msg instance (MonadPlus m) => MonadPlus (LabelT l m) where mzero = LabelT $ \_ -> mzero m `mplus` n = LabelT $ \l -> runLabelPrivT m l `mplus` runLabelPrivT n l instance (MonadFix m) => MonadFix (LabelT l m) where mfix f = LabelT $ \l -> mfix $ \a -> runLabelPrivT (f a) l instance MonadTrans (LabelT l) where lift m = LabelT $ \_ -> m instance (MonadIO m) => MonadIO (LabelT l m) where liftIO = lift . liftIO -} {- instance Monad m => Applicative (LabelT l m) where pure = return (<*>) = ap -} fmapReaderT :: (Functor f) => (a -> b) -> ReaderT r f a -> ReaderT r f b fmapReaderT f m = ReaderT $ \l -> fmap f $ runReaderT m l instance (Functor m) => Functor (LabelT l m) where fmap f m = LabelT $ fmapReaderT f $ runLabelPrivT m pureReaderT :: (Applicative f) => a -> ReaderT r f a pureReaderT a = ReaderT $ const $ pure a apReaderT :: (Applicative f) => ReaderT r f (a -> b) -> ReaderT r f a -> ReaderT r f b apReaderT f x = ReaderT $ \r -> runReaderT f r <*> runReaderT x r instance Applicative m => Applicative (LabelT l m) where pure a = LabelT $ pureReaderT a f <*> x = LabelT $ runLabelPrivT f `apReaderT` runLabelPrivT x runLabelT :: Monad m => LabelT l m a -> [l] -> m a runLabelT = runReaderT . runLabelPrivT askT :: Monad m => LabelT l m [l] askT = LabelT Reader.ask localT :: Monad m => l -> LabelT l m a -> LabelT l m a localT l m = LabelT $ Reader.local (l:) $ runLabelPrivT m