我了解到Monad.Reader实际上是一个函数的封装,即:
newtype Reader r a = Reader { runReader :: r -> a }
这是Monad的一个实例,
instance Monad (Reader r) where
return a = Reader $ \_ -> a
m >>= k = Reader $ \r -> runReader (k (runReader m r)) r
相反,我知道( - >)也是Monad,
instance Monad ((->) r) where
return = const
f >>= k = \ r -> k (f r) r
从定义中可以看出它们实际上的行为完全相同。
所有用法都可以互换吗?那两个Monad不同的实际意义是什么?
答案 0 :(得分:9)
他们是一样的。
State
,Writer
和Reader
的灵感来自Mark P. Jones'Functional Programming with Overloading and
Higher-Order Polymorphism,他在此定义Reader
如下:
Reader
monad用于允许计算访问所持有的值 在一些封闭环境中(由以下类型r
表示) 定义)。> instance Monad (r->) where > result x = \r -> x > x `bind` f = \r -> f (x r) r
作为传递评论,有趣的是要注意这两个功能 只是组合逻辑的标准
K
和S
组合。
后来,他定义了(几乎)今天的MonadReader
:
Reader monads
:一类monad,用于描述咨询某些固定环境的计算:> class Monad m => ReaderMonad m r where > env :: r -> m a -> m a > getenv :: m r > instance ReaderMonad (r->) r where > env e c = \_ -> c e > getenv = id
getenv
只是ask
,env
是local . const
。因此,该定义已包含Reader
的所有重要部分。最终,琼斯定义了monad变换器ReaderT
(BComp
是向后组合):
首先,定义两种不同形式的构图是有用的;转发(
FComp
)和倒退(BComp
):> data FComp m n a = FC (n (m a)) > data BComp m n a = BC (m (n a))
[省略Functor,Monad和OutOf实例]
> type ReaderT r = BComp (r ->)
由于StateT
,WriterT
和其他人拥有非转换变体,因此只有Reader r
才符合逻辑,这与(->) r
完全相同。
无论哪种方式,现在Reader
,Writer
和State
都是根据变换器变体定义的,并且您使用各自的Monad*
类型类(MonadReader
)。
所有用法都可以互换吗?
是
这两个Monads的不同之处是什么?
无,除了 ReaderT
实际上是一个monad变换器,这使事情变得更容易。
答案 1 :(得分:1)
它们都是MonadReader
class的实例。所以是的,你可以使用一个而不是另一个。
答案 2 :(得分:0)
toArrow :: Reader r a -> r -> a
和toReader :: (r -> a) -> Reader r a
实施toReader = Reader
和toArrow = runReader
。
编辑:Reader
背后的语义是它拥有一些只读配置,您可以通过您的计算链进行操作。
当你想要传递一些配置信息时,你应该总是更喜欢Reader
使用普通箭头类型,因为它是提供有用辅助函数的非常通用接口的一部分,用于操作MonadReader
类Reader
{1}}类似于数据类型,ReaderT
用于堆叠Monad
s。