mtl-unleashed-0.3.1: Control/Monad/Readers.hs
-- | MonadState without the function dependency @m -> s@.
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Control.Monad.Readers
( module Control.Monad.Reader
, magnify'
, MonadReaders(ask, local)
, asks
, view, views, iview, iviews
, preview, previews, ipreview, ipreviews
, review, reviews
, Magnify(magnify)
) where
import Control.Lens as Lens hiding (view, iview, views, uses, iviews, preview, previews, ipreview, ipreviews, review, reviews, Magnify)
import Control.Lens.Internal.Zoom (Magnified)
import Control.Monad.Reader hiding (MonadReader(ask, local, reader), asks)
import qualified Control.Monad.Reader as MTL (ask, local)
import Control.Monad.State (mapStateT, StateT)
import Control.Monad.Writer (WriterT, mapWriterT)
import Data.Monoid
import Data.Profunctor.Unsafe
import Data.Tagged
-- | Version of MonadReader modified to remove the functional dependency.
class Monad m => MonadReaders r m where
ask :: m r
ask = reader id
local :: (r -> r) -> m a -> m a
reader :: (r -> a) -> m a
reader f = do
r <- ask
return (f r)
instance Monad m => MonadReaders r (ReaderT r m) where
ask = MTL.ask
local = MTL.local
instance (Monad m, MonadReaders r m) => MonadReaders r (StateT s m) where
ask = lift ask
local = mapStateT . local
instance (Monad m, Monoid w, MonadReaders r m) => MonadReaders r (WriterT w m) where
ask = lift ask
local = mapWriterT . local
{-
-- Here is how you create a MonadReaders instance for a type that is
-- nested inside another MonadReaders instances. You need to declare
-- this with the exact parent type (here Bar) or you will get
-- overlapping instances.
instance (Monad m, MonadReaders Foo m) => MonadReaders Foo (ReaderT Bar m) where
ask = lift ask
local f action = MTL.ask >>= runReaderT (local f (lift action))
-}
-- | Retrieves a function of the current environment.
asks :: MonadReaders r m
=> (r -> a) -- ^ The selector function to apply to the environment.
-> m a
asks = reader
view :: MonadReaders s m => Getting a s a -> m a
view l = Control.Monad.Readers.asks (getConst #. l Const)
views :: (Profunctor p, MonadReaders s m) => Optical p (->) (Const r) s s a a -> p a r -> m r
views l f = Control.Monad.Readers.asks (getConst #. l (Const #. f))
iview :: MonadReaders s m => IndexedGetting i (i,a) s a -> m (i,a)
iview l = Control.Monad.Readers.asks (getConst #. l (Indexed $ \i -> Const #. (,) i))
iviews :: MonadReaders s m => IndexedGetting i r s a -> (i -> a -> r) -> m r
iviews l = views l .# Indexed
review :: MonadReaders b m => AReview t b -> m t
review p = asks (runIdentity #. unTagged #. p .# Tagged .# Identity)
reviews :: MonadReaders b m => AReview t b -> (t -> r) -> m r
reviews p tr = asks (tr . runIdentity #. unTagged #. p .# Tagged .# Identity)
instance MonadReaders s (ReifiedGetter s) where
ask = Getter id
{-# INLINE ask #-}
local f m = Getter (to f . runGetter m)
{-# INLINE local #-}
instance MonadReaders s (ReifiedFold s) where
ask = Fold id
{-# INLINE ask #-}
local f m = Fold (to f . runFold m)
{-# INLINE local #-}
preview :: MonadReaders s m => Getting (First a) s a -> m (Maybe a)
preview l = asks (getFirst #. foldMapOf l (First #. Just))
ipreview :: MonadReaders s m => IndexedGetting i (First (i, a)) s a -> m (Maybe (i, a))
ipreview l = asks (getFirst #. ifoldMapOf l (\i a -> First (Just (i, a))))
previews :: MonadReaders s m => Getting (First r) s a -> (a -> r) -> m (Maybe r)
previews l f = asks (getFirst . foldMapOf l (First #. Just . f))
ipreviews :: MonadReaders s m => IndexedGetting i (First r) s a -> (i -> a -> r) -> m (Maybe r)
ipreviews l f = asks (getFirst . ifoldMapOf l (\i -> First #. Just . f i))
class (Magnified m ~ Magnified n, MonadReaders b m, MonadReaders a n) => Magnify m n b a | m -> b, n -> a, m a -> n, n b -> m where
magnify :: LensLike' (Magnified m c) a b -> m c -> n c
-- | I don't know why Control.Lens.magnify isn't working for me.
magnify' :: forall r s m b. MonadReaders s m => Getting r s r -> ReaderT r m b -> m b
magnify' lns action = view lns >>= runReaderT action