class Monad m => MonadReader r m | m -> r 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 => MonadReader r (ReaderT r m) where ask = ReaderT.ask local = ReaderT.local reader = ReaderT.reader asks :: MonadReader r m => (r -> a) -> m a asks = reader
class Monad m => MonadReader r m | m -> r where
MonadReader 是個類型類,它爲 ReaderT, RWST 等具備 Reader 功能的 Monad 定義了通用接口。
所謂 Reader 功能是指第一個參數固定的函數,也就是具備固定環境變量的函數。
MonadReader 包含三個函數:ask, local, reader。
ask 獲取環境變量 r。
local f m 經過調用函數 f 局部性地修改環境變量 r,而後調用 Monad m 中封裝的函數。
reader f 對環境變量 r 調用指定函數 f。
另外同一個模塊中還定義了 asks 函數,它與 reader 函數同義。
What's the 「|」 for in a Haskell class definition?git
instance Monad m => MonadReader r (ReaderT r m) where
ask = ReaderT.ask
對於 ReaderT 這個Monad轉換器來講,ask等函數的定義均由 ReaderT 模塊來提供。注意這裏點運算符的含義不是函數的合成而是受限名字。
Hackage - Where is the MonadReader implementation for ReaderT defined?github
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a } instance (Monad m) => Monad (ReaderT r m) where return = lift . return m >>= k = ReaderT $ \ r -> do a <- runReaderT m r runReaderT (k a) r instance MonadTrans (ReaderT r) where lift = liftReaderT liftReaderT :: m a -> ReaderT r m a liftReaderT m = ReaderT (const m)
證實 ReaderT r m 符合Monad法則: 1. return a >>= f ≡ f a return a >>= f ≡ (ReaderT $ \_ -> m a) >>= f ≡ ReaderT $ \r -> do {a <- runReaderT (ReaderT $ \_ -> m a) r; runReaderT (f a) r} ≡ ReaderT $ \r -> do {a <- (\_ -> m a) r; runReaderT (f a) r} ≡ ReaderT $ \r -> runReaderT (f a) r ≡ ReaderT $ runReaderT (f a) ≡ f a 2. m >>= return ≡ m m = ReaderT $ \r -> n a m >>= return ≡ ReaderT $ \r -> do {a <- runReaderT m r; runReaderT (return a) r} ≡ ReaderT $ \r -> do {a <- runReaderT (ReaderT $ \r -> n a) r; runReaderT (ReaderT $ \_ -> n a) r} ≡ ReaderT $ \r -> do {a <- (\r -> n a) r; (\_ -> n a) r} ≡ ReaderT $ \r -> n a ≡ m 3. (m >>= f) >>= g ≡ m >>= (\x -> f x >>= g) (m >>= f) >>= g ≡ (ReaderT $ \r -> do {a <- runReaderT m r; runReaderT (f a) r}) >> g ≡ ReaderT $ \r -> do {a <- runReaderT (ReaderT $ \r -> do {a <- runReaderT m r; runReaderT (f a) r}) r; runReaderT (g a) r} ≡ ReaderT $ \r -> do {a <- (\r -> do {a <- runReaderT m r; runReaderT (f a) r}) r; runReaderT (g a) r} ≡ ReaderT $ \r -> do {a <- do {a <- runReaderT m r; runReaderT (f a) r}; runReaderT (g a) r} ≡ ReaderT $ \r -> (runReaderT m r >>= \a -> runReaderT (f a) r}) >>= \a -> runReaderT (g a) r m >>= (\x -> f x >>= g) ≡ ReaderT $ \r -> do {a <- runReaderT m r; runReaderT ((\x -> f x >>= g) a) r} ≡ ReaderT $ \r -> do {a <- runReaderT m r; runReaderT (f a >>= g) r} ≡ ReaderT $ \r -> do {a <- runReaderT m r; runReaderT (ReaderT $ \r -> do {a <- runReaderT (f a) r; runReaderT (g a) r}) r} ≡ ReaderT $ \r -> do {a <- runReaderT m r; (\r -> do {a <- runReaderT (f a) r; runReaderT (g a) r}) r} ≡ ReaderT $ \r -> do {a <- runReaderT m r; do {a <- runReaderT (f a) r; runReaderT (g a) r}} ≡ ReaderT $ \r -> runReaderT m r >>= (\a -> runReaderT (f a) r >>= \a -> runReaderT (g a) r) 根據內部 Monad 的法則:(m >>= f) >>= g ≡ m >>= (\x -> f x >>= g) ReaderT $ \r -> (runReaderT m r >>= \a -> runReaderT (f a) r}) >>= \a -> runReaderT (g a) r ≡ ReaderT $ \r -> runReaderT m r >>= (\a -> (\a -> runReaderT (f a) r}) a >>= \a -> runReaderT (g a) r) ≡ ReaderT $ \r -> runReaderT m r >>= (\a -> runReaderT (f a) r >>= \a -> runReaderT (g a) r)
證實 ReaderT 中 lift 函數的定義符合 lift 的法則。 1. lift . return ≡ return lift . return $ a ≡ ReaderT (const (return a)) ≡ ReaderT (const (m a)) ≡ ReaderT $ \_ -> m a ≡ return a 2. lift (m >>= f) ≡ lift m >>= (lift . f) 假設 m = n a 而且 f a = n b 因而 m >>= f = n b lift (m >>= f) ≡ ReaderT (const (n b)) ≡ ReaderT $ \_ -> n b lift m >>= (lift . f) ≡ ReaderT (const (n a)) >>= (ReaderT . const . f) ≡ (ReaderT $ \_ -> n a) >>= (\x -> ReaderT . const . f $ x) ≡ ReaderT $ \_ -> runReaderT (ReaderT . const . f $ a) _ ≡ ReaderT $ \_ -> runReaderT (ReaderT (const (n b)) _ ≡ ReaderT $ \_ -> runReaderT (ReaderT (\_ -> n b) _ ≡ ReaderT $ \_ -> n b
ask :: (Monad m) => ReaderT r m r ask = ReaderT return local :: (Monad m) => (r -> r) -> ReaderT r m a -> ReaderT r m a local = withReaderT reader :: (Monad m) => (r -> a) -> ReaderT r m a reader f = ReaderT (return . f) asks :: (Monad m) => (r -> a) -> ReaderT r m a asks f = ReaderT (return . f) mapReaderT :: (m a -> n b) -> ReaderT r m a -> ReaderT r n b mapReaderT f m = ReaderT $ f . runReaderT m withReaderT :: (r' -> r) -> ReaderT r m a -> ReaderT r' m a withReaderT f m = ReaderT $ runReaderT m . f
withReaderT :: (r' -> r) -> ReaderT r m a -> ReaderT r' m a
withReaderT f m = ReaderT $ runReaderT m . f
withReaderT f m 經過調用函數 f 局部性地修改環境變量 r,而後調用 Monad m 中封裝的函數。函數
local :: (Monad m) => (r -> r) -> ReaderT r m a -> ReaderT r m a
local = withReaderT
withReaderT 與 local 的區別在於 withReaderT 可以改變環境變量 r 的類型。
local 不能改變環境變量 r 的類型,它能夠被看作 withReaderT 的特例。code
Prelude Control.Monad.Reader> runReaderT ask "abc" "abc" Prelude Control.Monad.Reader> runReaderT (local (++ "def") ask) "abc" "abcdef" Prelude Control.Monad.Reader> runReaderT (withReaderT length ask) "abc" 3 Prelude Control.Monad.Reader> runReaderT (mapReaderT (++ ["def"]) ask) "abc" ["abc","def"] Prelude Control.Monad.Reader> runReaderT (asks (++ "def")) "abc" "abcdef" Prelude Control.Monad.Reader> runReaderT (local (++ "def") ask >> ask) "abc" "abc" Prelude Control.Monad.Reader> let ioTask = do {v <- ask; liftIO $ print v} Prelude Control.Monad.Reader> :t ioTask ioTask :: (MonadReader a m, MonadIO m, Show a) => m () Prelude Control.Monad.Reader> runReaderT ioTask "abc" "abc" Prelude Control.Monad.Reader> runReaderT (local (++ "def") ioTask) "abc" "abcdef" Prelude Control.Monad.Reader> runReaderT (local (++ "def") ioTask >> ioTask) "abc" "abcdef" "abc"
type Reader r = ReaderT r Identity runReader :: Reader r a -> r -> a runReader m = runIdentity . runReaderT m mapReader :: (a -> b) -> Reader r a -> Reader r b mapReader f = mapReaderT (Identity . f . runIdentity) withReader :: (r' -> r) -> Reader r a -> Reader r' a withReader = withReaderT
Reader Monad 是 ReaderT Monad(轉換器) 的一個特例。接口
Prelude Control.Monad.Reader> runReader (mapReader (++"def") ask) "abc" "abcdef" Prelude Control.Monad.Reader> runReader (withReader (++"def") ask) "abc" "abcdef"
import Control.Monad.Reader hello :: Reader String String hello = do name <- ask return ("hello, " ++ name ++ "!") bye :: Reader String String bye = do name <- ask return ("bye, " ++ name ++ "!") convo :: Reader String String convo = do c1 <- hello c2 <- bye return $ c1 ++ c2 main = print . runReader convo $ "adit"
import Control.Monad.Reader hello :: Reader String String hello = asks $ \name -> ("hello, " ++ name ++ "!") bye :: Reader String String bye = asks $ \name -> ("bye, " ++ name ++ "!") convo :: Reader String String convo = asks (const (++)) <*> hello <*> bye main = print . runReader convo $ "adit"