MonadReader 类型类

  1. class Monad m => MonadReader r m | m -> r where
  2. ask :: m r
  3. ask = reader id
  4. local :: (r -> r) -> m a -> m a
  5. reader :: (r -> a) -> m a
  6. reader f = do
  7. r <- ask
  8. return (f r)
  9. instance Monad m => MonadReader r (ReaderT r m) where
  10. ask = ReaderT.ask
  11. local = ReaderT.local
  12. reader = ReaderT.reader
  13. asks :: MonadReader r m => (r -> a) -> m a
  14. 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?

  • 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?

ReaderT Monad转换器

  1. newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
  2. instance (Monad m) => Monad (ReaderT r m) where
  3. return = lift . return
  4. m >>= k = ReaderT $ \ r -> do
  5. a <- runReaderT m r
  6. runReaderT (k a) r
  7. instance MonadTrans (ReaderT r) where
  8. lift = liftReaderT
  9. liftReaderT :: m a -> ReaderT r m a
  10. liftReaderT m = ReaderT (const m)
  • newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }

    ReaderT 类型是个 newtype,也就是对现有类型的封装。该类型有三个类型参数:内部 Monad 类型参数 m,共享环境类型参数 r 以及结果类型参数 a。

    ReaderT r m a 类型封装了一个共享环境计算函数:\r -> m a,通过 runReaderT 字段可以从 ReaderT 类型中取出这个函数。
  • instance (Monad m) => Monad (ReaderT r m) where

    如果 m 是个 Monad,那么 ReaderT r m 也是一个 Monad。

    对比 Monad 类型类的定义,可知 return 函数的类型签名为:

    return :: a -> ReaderT r m a

    大致相当于 a -> r -> m a

    而 bind 函数的类型签名为:

    (>>=) :: ReaderT r m a -> (a -> ReaderT r m b) -> ReaderT r m b

    大致相当于 (r -> m a) -> (a -> r -> m b) -> (r -> m b)
  • return = lift . return

    return 函数首先将类型为 a 的值封装进内部 Monad m 中,然后通过 lift 函数将它封装进 ReaderT 这个Monad 转换器之中。

    这里左侧的 return 是 ReaderT 这个 Monad 的 return,而右侧的 return 是内部 Monad m 的 return。
  • lift = liftReaderT

    liftReaderT m = ReaderT (const m)

    lift 函数的定义由 liftReaderT 函数提供。

    liftReaderT 函数首先将封装在内部 Monad m 中的值封装进常值函数 const 中,然后再将它封装进 ReaderT 这个Monad 转换器之中。

    return a

    = lift . return $ a

    = liftReaderT . return $ a

    = ReaderT (const (m a))

    = ReaderT $ _ -> m a
  • m >>= k = ReaderT $ \r -> do

    对比函数签名,可知 m 的类型是 ReaderT r m a

    而 k 的类型是 a -> Reader r m b
  • a <- runReaderT m r

    runReaderT m 让 m 脱离了 ReaderT 这个 Monad,而 <- 运算符让 runReaderT m r 脱离了内部 Monad m。
  • runReaderT (k a) r

    k a 的类型是 ReaderT r m b

    runReaderT (k a) 让 k a 脱离了 ReaderT 这个 Monad,重新进入内部 Monad m。
  1. 证明 ReaderT r m 符合Monad法则:
  2. 1. return a >>= f f a
  3. return a >>= f
  4. (ReaderT $ \_ -> m a) >>= f
  5. ReaderT $ \r -> do {a <- runReaderT (ReaderT $ \_ -> m a) r; runReaderT (f a) r}
  6. ReaderT $ \r -> do {a <- (\_ -> m a) r; runReaderT (f a) r}
  7. ReaderT $ \r -> runReaderT (f a) r
  8. ReaderT $ runReaderT (f a)
  9. f a
  10. 2. m >>= return m
  11. m = ReaderT $ \r -> n a
  12. m >>= return
  13. ReaderT $ \r -> do {a <- runReaderT m r; runReaderT (return a) r}
  14. ReaderT $ \r -> do {a <- runReaderT (ReaderT $ \r -> n a) r; runReaderT (ReaderT $ \_ -> n a) r}
  15. ReaderT $ \r -> do {a <- (\r -> n a) r; (\_ -> n a) r}
  16. ReaderT $ \r -> n a
  17. m
  18. 3. (m >>= f) >>= g m >>= (\x -> f x >>= g)
  19. (m >>= f) >>= g
  20. (ReaderT $ \r -> do {a <- runReaderT m r; runReaderT (f a) r}) >> g
  21. ReaderT $ \r -> do {a <- runReaderT (ReaderT $ \r -> do {a <- runReaderT m r; runReaderT (f a) r}) r; runReaderT (g a) r}
  22. ReaderT $ \r -> do {a <- (\r -> do {a <- runReaderT m r; runReaderT (f a) r}) r; runReaderT (g a) r}
  23. ReaderT $ \r -> do {a <- do {a <- runReaderT m r; runReaderT (f a) r}; runReaderT (g a) r}
  24. ReaderT $ \r -> (runReaderT m r >>= \a -> runReaderT (f a) r}) >>= \a -> runReaderT (g a) r
  25. m >>= (\x -> f x >>= g)
  26. ReaderT $ \r -> do {a <- runReaderT m r; runReaderT ((\x -> f x >>= g) a) r}
  27. ReaderT $ \r -> do {a <- runReaderT m r; runReaderT (f a >>= g) r}
  28. ReaderT $ \r -> do {a <- runReaderT m r; runReaderT (ReaderT $ \r -> do {a <- runReaderT (f a) r; runReaderT (g a) r}) r}
  29. ReaderT $ \r -> do {a <- runReaderT m r; (\r -> do {a <- runReaderT (f a) r; runReaderT (g a) r}) r}
  30. ReaderT $ \r -> do {a <- runReaderT m r; do {a <- runReaderT (f a) r; runReaderT (g a) r}}
  31. ReaderT $ \r -> runReaderT m r >>= (\a -> runReaderT (f a) r >>= \a -> runReaderT (g a) r)
  32. 根据内部 Monad 的法则:(m >>= f) >>= g m >>= (\x -> f x >>= g)
  33. ReaderT $ \r -> (runReaderT m r >>= \a -> runReaderT (f a) r}) >>= \a -> runReaderT (g a) r
  34. ReaderT $ \r -> runReaderT m r >>= (\a -> (\a -> runReaderT (f a) r}) a >>= \a -> runReaderT (g a) r)
  35. ReaderT $ \r -> runReaderT m r >>= (\a -> runReaderT (f a) r >>= \a -> runReaderT (g a) r)
  1. 证明 ReaderT lift 函数的定义符合 lift 的法则。
  2. 1. lift . return return
  3. lift . return $ a
  4. ReaderT (const (return a))
  5. ReaderT (const (m a))
  6. ReaderT $ \_ -> m a
  7. return a
  8. 2. lift (m >>= f) lift m >>= (lift . f)
  9. 假设 m = n a 并且 f a = n b
  10. 于是 m >>= f = n b
  11. lift (m >>= f)
  12. ReaderT (const (n b))
  13. ReaderT $ \_ -> n b
  14. lift m >>= (lift . f)
  15. ReaderT (const (n a)) >>= (ReaderT . const . f)
  16. (ReaderT $ \_ -> n a) >>= (\x -> ReaderT . const . f $ x)
  17. ReaderT $ \_ -> runReaderT (ReaderT . const . f $ a) _
  18. ReaderT $ \_ -> runReaderT (ReaderT (const (n b)) _
  19. ReaderT $ \_ -> runReaderT (ReaderT (\_ -> n b) _
  20. ReaderT $ \_ -> n b

ReaderT Monad转换器的函数

  1. ask :: (Monad m) => ReaderT r m r
  2. ask = ReaderT return
  3. local :: (Monad m) => (r -> r) -> ReaderT r m a -> ReaderT r m a
  4. local = withReaderT
  5. reader :: (Monad m) => (r -> a) -> ReaderT r m a
  6. reader f = ReaderT (return . f)
  7. asks :: (Monad m) => (r -> a) -> ReaderT r m a
  8. asks f = ReaderT (return . f)
  9. mapReaderT :: (m a -> n b) -> ReaderT r m a -> ReaderT r n b
  10. mapReaderT f m = ReaderT $ f . runReaderT m
  11. withReaderT :: (r' -> r) -> ReaderT r m a -> ReaderT r' m a
  12. 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 的特例。

  1. Prelude Control.Monad.Reader> runReaderT ask "abc"
  2. "abc"
  3. Prelude Control.Monad.Reader> runReaderT (local (++ "def") ask) "abc"
  4. "abcdef"
  5. Prelude Control.Monad.Reader> runReaderT (withReaderT length ask) "abc"
  6. 3
  7. Prelude Control.Monad.Reader> runReaderT (mapReaderT (++ ["def"]) ask) "abc"
  8. ["abc","def"]
  9. Prelude Control.Monad.Reader> runReaderT (asks (++ "def")) "abc"
  10. "abcdef"
  11. Prelude Control.Monad.Reader> runReaderT (local (++ "def") ask >> ask) "abc"
  12. "abc"
  13. Prelude Control.Monad.Reader> let ioTask = do {v <- ask; liftIO $ print v}
  14. Prelude Control.Monad.Reader> :t ioTask
  15. ioTask :: (MonadReader a m, MonadIO m, Show a) => m ()
  16. Prelude Control.Monad.Reader> runReaderT ioTask "abc"
  17. "abc"
  18. Prelude Control.Monad.Reader> runReaderT (local (++ "def") ioTask) "abc"
  19. "abcdef"
  20. Prelude Control.Monad.Reader> runReaderT (local (++ "def") ioTask >> ioTask) "abc"
  21. "abcdef"
  22. "abc"

Reader Monad

  1. type Reader r = ReaderT r Identity
  2. runReader :: Reader r a -> r -> a
  3. runReader m = runIdentity . runReaderT m
  4. mapReader :: (a -> b) -> Reader r a -> Reader r b
  5. mapReader f = mapReaderT (Identity . f . runIdentity)
  6. withReader :: (r' -> r) -> Reader r a -> Reader r' a
  7. withReader = withReaderT

Reader Monad 是 ReaderT Monad(转换器) 的一个特例。

  1. Prelude Control.Monad.Reader> runReader (mapReader (++"def") ask) "abc"
  2. "abcdef"
  3. Prelude Control.Monad.Reader> runReader (withReader (++"def") ask) "abc"
  4. "abcdef"

应用实例

  1. import Control.Monad.Reader
  2. hello :: Reader String String
  3. hello = do
  4. name <- ask
  5. return ("hello, " ++ name ++ "!")
  6. bye :: Reader String String
  7. bye = do
  8. name <- ask
  9. return ("bye, " ++ name ++ "!")
  10. convo :: Reader String String
  11. convo = do
  12. c1 <- hello
  13. c2 <- bye
  14. return $ c1 ++ c2
  15. main = print . runReader convo $ "adit"
  1. import Control.Monad.Reader
  2. hello :: Reader String String
  3. hello = asks $ \name -> ("hello, " ++ name ++ "!")
  4. bye :: Reader String String
  5. bye = asks $ \name -> ("bye, " ++ name ++ "!")
  6. convo :: Reader String String
  7. convo = asks (const (++)) <*> hello <*> bye
  8. main = print . runReader convo $ "adit"

Reader monad example

Haskell语言学习笔记(23)MonadReader, Reader, ReaderT的更多相关文章

  1. Haskell语言学习笔记(88)语言扩展(1)

    ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...

  2. Haskell语言学习笔记(79)lambda演算

    lambda演算 根据维基百科,lambda演算(英语:lambda calculus,λ-calculus)是一套从数学逻辑中发展,以变量绑定和替换的规则,来研究函数如何抽象化定义.函数如何被应用以 ...

  3. Haskell语言学习笔记(69)Yesod

    Yesod Yesod 是一个使用 Haskell 语言的 Web 框架. 安装 Yesod 首先更新 Haskell Platform 到最新版 (Yesod 依赖的库非常多,版本不一致的话很容易安 ...

  4. Haskell语言学习笔记(20)IORef, STRef

    IORef 一个在IO monad中使用变量的类型. 函数 参数 功能 newIORef 值 新建带初值的引用 readIORef 引用 读取引用的值 writeIORef 引用和值 设置引用的值 m ...

  5. Haskell语言学习笔记(39)Category

    Category class Category cat where id :: cat a a (.) :: cat b c -> cat a b -> cat a c instance ...

  6. Haskell语言学习笔记(37)RWS, RWST

    RWST Monad转换器 RWST Monad转换器是将 ReaderT, WriterT 以及 StateT 这三个Monad转换器的功能集于一体的产物. newtype RWST r w s m ...

  7. Haskell语言学习笔记(30)MonadCont, Cont, ContT

    MonadCont 类型类 class Monad m => MonadCont m where callCC :: ((a -> m b) -> m a) -> m a in ...

  8. Haskell语言学习笔记(25)MonadState, State, StateT

    MonadState 类型类 class Monad m => MonadState s m | m -> s where get :: m s get = state (\s -> ...

  9. Haskell语言学习笔记(24)MonadWriter, Writer, WriterT

    MonadWriter 类型类 class (Monoid w, Monad m) => MonadWriter w m | m -> w where writer :: (a,w) -& ...

随机推荐

  1. python3 获取int最大值

    python2 中获取int最大值 import sys i = sys.maxint print i 但是在python3中,报错: AttributeError: module 'sys' has ...

  2. c 结构体的队列

    头文件 lsg_queue.h #pragma once #include<stdbool.h> /* 链式栈接口的定义头文件 */ #define true 1 #define fals ...

  3. Oracle RAC的机制与测试方法

    Oracle RAC的机制与测试方法 标签: rac 机制 测试 2016-05-25 09:54 1150人阅读 评论(0) 收藏 举报  分类: oracle(2)  1.RAC原理 Oracle ...

  4. REDHAT中的iptable设置(nginx或者apache80端口访问不了解决)转 亲测

    来自:http://johnnychenjun.blog.163.com/blog/static/137493406201010284598972/ 查看当前防火墙里的状态:#/etc/init.d/ ...

  5. C/C++基础----类

    IO类属于不能被拷贝的类型,因此只能通过引用来传递.同时读取和写入操作都会改变流的内容,所以接收的是普通引用. 类内的友元声明仅仅指定了访问的权限,需要在友元声明之外再专门对函数进行一次声明. 可变数 ...

  6. bzoj3871: [Neerc2013 C]Cactus Automorphisms || 3899: 仙人掌树的同构

    Description 给定一个N,N<=50 000个节点的仙人掌,其是指每条边最多在一个环中的无向图,求仙人掌有多少种自同构.自同构是指得是图的顶点集合V到V的变换M, 以P1^a1*P2^ ...

  7. HDU 2159 FATE (dp)

    FATE Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submissi ...

  8. IE, Firefox下,checkbox的钩钩一旦勾上,画面再刷新,钩钩还是勾上的解决方案

    如题,IE, Firefox下,checkbox的钩钩一旦勾上,画面再刷新,钩钩还是勾上的解决方案 <input type="checkbox"  />加上属性auto ...

  9. PostMan 使用Interceptor 发送带cookie的请求一直loading

    问题 最近要写一个爬虫(虽然是第一次写),于是就用了Chrome上非常方便一个插件,PostMan,但是由于chrome安全的限制,发不出带cookie和带有自定义头部标签的请求. 百度一番后得如果想 ...

  10. [UE4]运行时UMG组件跟随鼠标的逻辑:拖拽UMG组件(蓝图)

    转自:http://aigo.iteye.com/blog/2279860 UMG - Mouse screen position problem https://forums.unrealengin ...