Monad.Reader 和 (->) monads 有什么区别?



我知道了莫纳德。阅读器实际上是一个函数的封装,即:

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

从定义中可以看出,它们实际上的行为完全相同。

那么,它们在所有用途中都可以互换吗?区别这两个君主的实际意义是什么?

TL;DR

他们是一样的。

一些历史课

StateWriterReader的设计灵感来自于Mark p.Jones的重载函数程序设计高阶多态性,他将Reader定义如下:

Reader monad用于允许计算访问所保存的值在某些封闭环境中(由下面的类型r表示定义)。

> instance Monad (r->) where
>     result x = r -> x
>     x `bind` f = r -> f (x r) r

顺便说一句,有趣的是注意到这两个函数只是组合逻辑的标准CCD_ 7和CCD_。

后来,他定义了(几乎)今天的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,而envlocal . const。因此,这个定义已经包含了Reader的所有重要部分。最终,Jones定义了monad转换器ReaderTBComp是反向合成):

首先,定义两种不同形式的作文是有用的;向前(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 ->)

由于StateTWriterT和其他类型都有其非变换器变体,因此只有Reader r才是合乎逻辑的,它实际上与(->) r相同。

无论哪种方式,现在ReaderWriterState都是根据它们的转换器变体来定义的,并且您使用它们各自的Monad*类型类(MonadReader)。

结论

那么,它们在所有用途中都可以互换吗?

是的。

区别这两个君主的实际意义是什么?

没有,除了ReaderT实际上是一个monad转换器,这让事情变得更容易。

它们都是MonadReader类的实例。所以是的,你可以用一个代替另一个。

它们实际上是完全相同的。我们可以通过在它们之间进行映射来使其更加正式:toArrow :: Reader r a -> r -> atoReader :: (r -> a) -> Reader r a实现方式为CCD_ 33和CCD_。

编辑:Reader背后的语义是,它包含一些只读配置,您可以通过计算链进行处理。当您想要处理一些配置信息时,您应该始终更喜欢Reader而不是使用纯箭头类型,因为它是一个非常通用的接口的一部分,该接口提供了有用的辅助函数,一个用于操作类似Reader的数据类型的MonadReader类,以及一个用于堆叠Monad s的ReaderT

最新更新