linear-base-0.2.0: src/Control/Functor/Linear/Internal/Reader.hs
{-# OPTIONS -Wno-orphans #-}
{-# LANGUAGE LinearTypes #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_HADDOCK hide #-}
module Control.Functor.Linear.Internal.Reader
( -- ReaderT monad transformer
Reader,
reader,
runReader,
mapReader,
withReader,
ReaderT (..),
runReaderT,
mapReaderT,
withReaderT,
ask,
local,
asks,
)
where
import Control.Functor.Linear.Internal.Class
import Control.Functor.Linear.Internal.Instances ()
import Control.Functor.Linear.Internal.MonadTrans
import qualified Control.Monad as NonLinear ()
import qualified Control.Monad.Trans.Reader as NonLinear
import Data.Functor.Identity
import qualified Data.Functor.Linear.Internal.Applicative as Data
import qualified Data.Functor.Linear.Internal.Functor as Data
import Data.Unrestricted.Linear.Internal.Consumable
import Data.Unrestricted.Linear.Internal.Dupable
import Prelude.Linear.Internal (runIdentity', ($), (.))
-- # Linear ReaderT
-------------------------------------------------------------------------------
-- | A linear reader monad transformer.
-- This reader monad requires that use of the read-only state is explict.
--
-- The monad instance requires that @r@ be 'Dupable'. This means that you
-- should use the linear reader monad just like the non-linear monad, except
-- that the type system ensures that you explicity use or discard the
-- read-only state (with the 'Consumable' instance).
newtype ReaderT r m a = ReaderT (r %1 -> m a)
-- XXX: Replace with a newtype deconstructor once it can be inferred as linear.
-- | Provide an intial read-only state and run the monadic computation in
-- a reader monad transformer
runReaderT :: ReaderT r m a %1 -> r %1 -> m a
runReaderT (ReaderT f) = f
instance Data.Functor m => Data.Functor (ReaderT r m) where
fmap f = mapReaderT (Data.fmap f)
instance Functor m => Functor (ReaderT r m) where
fmap f = mapReaderT (fmap f)
instance (Data.Applicative m, Dupable r) => Data.Applicative (ReaderT r m) where
pure x = ReaderT $ \r -> lseq r (Data.pure x)
ReaderT f <*> ReaderT x = ReaderT ((\(r1, r2) -> f r1 Data.<*> x r2) . dup)
instance (Applicative m, Dupable r) => Applicative (ReaderT r m) where
pure x = ReaderT $ \r -> lseq r (pure x)
ReaderT f <*> ReaderT x = ReaderT ((\(r1, r2) -> f r1 Data.<*> x r2) . dup)
instance (Monad m, Dupable r) => Monad (ReaderT r m) where
ReaderT x >>= f = ReaderT ((\(r1, r2) -> x r1 >>= (\a -> runReaderT (f a) r2)) . dup)
type Reader r = ReaderT r Identity
ask :: Applicative m => ReaderT r m r
ask = ReaderT pure
withReaderT :: (r' %1 -> r) %1 -> ReaderT r m a %1 -> ReaderT r' m a
withReaderT f m = ReaderT $ runReaderT m . f
local :: (r %1 -> r) %1 -> ReaderT r m a %1 -> ReaderT r m a
local = withReaderT
reader :: Monad m => (r %1 -> a) %1 -> ReaderT r m a
reader f = ReaderT (return . f)
runReader :: Reader r a %1 -> r %1 -> a
runReader m = runIdentity' . runReaderT m
mapReader :: (a %1 -> b) %1 -> Reader r a %1 -> Reader r b
mapReader f = mapReaderT (Identity . f . runIdentity')
mapReaderT :: (m a %1 -> n b) %1 -> ReaderT r m a %1 -> ReaderT r n b
mapReaderT f m = ReaderT (f . runReaderT m)
withReader :: (r' %1 -> r) %1 -> Reader r a %1 -> Reader r' a
withReader = withReaderT
asks :: Monad m => (r %1 -> a) %1 -> ReaderT r m a
asks f = ReaderT (return . f)
instance Dupable r => MonadTrans (ReaderT r) where
lift x = ReaderT (`lseq` x)
-- # Instances for nonlinear ReaderT
-------------------------------------------------------------------------------
instance Functor m => Functor (NonLinear.ReaderT r m) where
fmap f (NonLinear.ReaderT g) = NonLinear.ReaderT $ \r -> fmap f (g r)
instance Applicative m => Applicative (NonLinear.ReaderT r m) where
pure x = NonLinear.ReaderT $ \_ -> pure x
NonLinear.ReaderT f <*> NonLinear.ReaderT x = NonLinear.ReaderT $ \r -> f r <*> x r
instance Monad m => Monad (NonLinear.ReaderT r m) where
NonLinear.ReaderT x >>= f = NonLinear.ReaderT $ \r -> x r >>= (\a -> runReaderT' (f a) r)
-- XXX: Temporary, until newtype record projections are linear.
runReaderT' :: NonLinear.ReaderT r m a %1 -> r -> m a
runReaderT' (NonLinear.ReaderT f) = f
instance MonadTrans (NonLinear.ReaderT r) where
lift x = NonLinear.ReaderT (\_ -> x)