混淆ReaderT定义



作为练习,我一直在重新实现一些常见的单子和它们相应的转换器;以下是我定义的一些类型:

newtype Writer  w   a = Writer  { runWriter  :: (w, a) }
newtype WriterT w m a = WriterT { runWriterT :: m (Writer w a) }
newtype Maybe    a = Just a | Nothing
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }

当我得到一个变压器"包装"一个单子在一个外部单子m;根据这种直觉,我尝试以类似的方式定义ReaderT变压器:

newtype Reader  r   a = Reader  { runReader  :: r -> a }
newtype ReaderT r m a = ReaderT { runReaderT :: m (Reader r a) }

然而,我在实现它的monad实例时遇到了困难。通过查看ReaderT的库定义,我看到它被定义为

newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }

除了它不使用Reader(可以用ReaderT来定义),为什么它被定义为r -> m a而不是m (r -> a)?我认为它应该包装内部Reader(即r -> a)与外部单子m获得m (r -> a),而不是r -> m a

m (r -> a)意味着你:

  1. 首先在单子中执行一些操作,然后,

  2. 动作完成后,对reader值执行纯计算。

但是你需要能够使用ask:

ask :: Monad m => ReaderT r m r

使用ask,您可以:

  1. 首先读取值,

  2. 然后执行一些单元操作,作用于值。

这就是为什么r -> m a有意义而m (r -> a)没有意义。

如果有帮助,可以将其视为与writer单子"对称"。对于写单子,单子在外面,结果在里面。对于阅读器单子,输入在外面,单子在里面。这种对称经常出现。

相关内容

  • 没有找到相关文章

最新更新